View on
MetaCPAN is shutting down
For details read Perl NOC. After June 25th this page will redirect to
Руслан У. Закиров > RT-Extension-TicketAging > RT::Extension::TicketAging



Annotate this POD

View/Report Bugs
Module Version: 0.12   Source  


RT::Extension::TicketAging - allows tickets to be made inaccessable and finally completely deleted


This extension allows closed tickets to be made inaccessable and finally completely deleted as they get older. It adds a new global ticket field, "Age", to track a ticket's movement through the life cycle.

The rt-aging program (see below) is used to move tickets through the life cycle and must be run separately.

When we speak of "age" we are referring to a ticket's "LastUpdated" property.

Default life cycle

The default life cycle is:


Any unresolved ticket or a ticket with unresolved children is considered Active.


When a ticket and all its children have been resolved it becomes Finished. No further activity is expected on this ticket.

There is otherwise nothing special about a Finished ticket.


When a ticket and all its children are Finished and it has not been updated for 2 months it becomes Dead. Dead tickets are just like Finished tickets except they do not show up in RTIR's special lookup tools.


When a ticket is Dead and has not been updated for 12 months it becomes Extinct. Extinct tickets have their status set to deleted. They won't show up in any searches unless explicitly asked for ('CF.{Age} = "Extinct"').


When a ticket is Extinct and has not been updated for 24 months and if all linked tickets are also Extinct a ticket is Destroyed. Destroyed tickets are no longer available in RT. They are wholely removed from RT using the Shredder. Destroyed tickets are saved in a SQL dump file from which they can be restored.

See RT::Shredder for more information.


When users reopen a ticket (change Status from inactive to active) it becomes Active again.


The real work is done by the rt-aging program installed to your RT local sbin. In general you simply run rt-aging from the command line or periodically from cron as an RT administrator. It will apply the aging rules and alter the tickets as necessary.

See rt-aging for more details.

Aging configuration

Library preloading

Add the line use RT::Extension::TicketAging;

to the bottom of the RT site config, etc/ after adding all extension options described below.

This step is required to allow users to search by Extinct age.


By default we grant SeeCustomField right to all privileged users.


This is the filename template used to create the Shredder dump file when tickets are Destroyed. Defaults to the RT::Shredder default. Good candidates:

    Set($TicketAgingFilenameTemplate, 'aging-%t.XXXX.sql');
    # or
    Set($TicketAgingFilenameTemplate, '/var/backups/aging/%t.XXXX.sql');

See the documentation for <RT::Shredder-GetFileName>> for more details.



Administrators may define their own aging behaviors.

The ages available to RT are configured by changing the available values for the Age global custom field. An administrator may remove values to disable pre-configured options. Adding new values activates new age commands but if its not one of the above values you have to configure the conditions and actions for each age.

$TicketAgingMap can be set in your configuration to override or add to the default life cycle. Its easiest to illustrate this with code.

    Set( $TicketAgingMap, {
             AgeName => {
                 Condition => {
                     CallbackPre  => sub { ... },
                     SQL          => sub { ... },
                     CallbackPost => sub { ... },
                     Filter       => sub { ... },
                 Action => sub { ... }


The aging conditions and actions generally have these arguments:


This is the name of the age being processed. For example "Active".


This is an RT::Tickets object representing all the tickets visible to the $RT::SystemUser. It can be filtered by the Callbacks and the SQL.


An individual RT::Ticket from the ticket Collection.



The name of your Age field. For example, "Active".


Holds the rules for determining what tickets fall into this age. The rules are run in this order (excuse the pseudo-code):

    foreach $Object ($Collection) {

This is the TicketSQL to be run to get the tickets of this Age. Generally its a check against LastUpdated and perhaps Status.

    SQL => sub { "LastUpdated < '-2 months'" }

The TicketSQL is run against the Collection.

Called with Age and Collection arguments.

Should return a valid TicketSQL string.


These callbacks can be used to alter the Collection before the SQL is run or before the Filter.

Called with Age and Collection arguments.

Must return true on success or a tuple of (false, $error_message) on failure.

For example:

    # Search for deleted tickets
    CallbackPre => sub {
        my %args = @_;
        return $args{Collection}{allow_deleted_search} = 1;

Each ticket found by the SQL condition in the Collection is iterated over and the Filter is called on each one. This gives an opportunity to cull out individual tickets.

Called with Age, Collection and Object arguments. Object is an individual RT::Ticket from the ticket Collection.

Returns true if the ticket should be included in the age, false if it should be ignored.

    # Filter out tickets whose children are not of the same age.
    Filter => sub {
        my %args = @_;
        my $id = $args{Object}->id;

        my $find_different_children = qq{
              (CF.{Age} IS NULL OR CF.{Age} != $args{Age})
              AND Linked = $id

        my $tickets = RT::Tickets->new( $RT::SystemUser );
        $tickets->{allow_deleted_search} = 1;
        $tickets->FromSQL( $find_different_children );
        return !$tickets->Count;

After filtering, each ticket found in the Collection is iterated over and the Action is called on each one. This is where whatever changes that need to be made to individual tickets when they change age should be done.

Called with Age, Collection and Object arguments.

Like the Callbacks, it returns true on success or a tuple of (false, $error_message) on failure.

    # Mark the ticket as deleted.
    Action => sub {
        my %args = @_;
        my $ticket = $args{Object};

        return $ticket->__Set( Field => "Status", Value => "deleted" );


Ruslan Zakirov <>

syntax highlighting: