function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
MC2014MC2014 

Class within trigger doesn't finish execute in time?

I found this trigger and it seems that one of the past developer is doing an update  of an opportunity within the trigger instead with the class.

From what I understood, that the class will still be executing eventhough after the record page has been updated and reloaded for the end-user? Never experience this before, how about anyone here?

trigger Opp on Opportunity (after update) {
    for (Integer i = 0; i < Trigger.old.size(); i++) {
        Opportunity old = Trigger.old[i];
        Opportunity nw = Trigger.new[i];
        Boolean man = false;
      
        if ((nw.Probability == 100) && (old.Probability != nw.Probability)) {
      
            oppClose.createCase(nw.Id, man);
            //Clone statuses indicate different follow-up actions for people.
            if (nw.Clone_Status__c != 'Completed' && nw.Clone_Status__c != 'Non-renewable' && nw.Clone_Status__c != 'Exception') {
            oppClose.cloneOpp(nw.Id);
          
            /*Clone Status field is updated from the trigger instead of the the class. The class runs asynchronsously (ie. in the future)
            * so the results do not show up immediatley in the Opp after closing it won and returning to the saved record.
            * By updating the field in the trigger a flag is set to alert the user and to prevent a subsequent update from
            * triggering the class again if the async execution is delayed.
            */
            Opportunity opp = new Opportunity(
            Id = nw.Id,
            Clone_Status__c = 'Completed');
            update opp;
            }
        }
    }
Best Answer chosen by MC2014
GlynAGlynA
You are right that the trigger will complete, the DML will complete, the AJAX will complete and the page will be rerendered all before the @future method in the "oppClose" class executes.  This must be by design for some reason.  Web callouts is one reason, increased CPU execution time is another.

One thing I've noticed, though, is that this trigger is not bulk-safe.  It will work well with one (or a small number) of records, but you can only launch 10 @future methods per transaction.  If the trigger calls "oppClose.cloneOpp()" more than 10 times, the trigger will fail with an uncatchable exception.

The code in the next post is a refactor of the trigger that makes it bulk-safe.  You will need to modify both "oppClose.createCase" and "oppClose.cloneOpp" so that they take a set of IDs and create/clone multiple records.  I hope this is useful.

Glyn Anderson
Sr Developer | System Analyst | ClosedWon | closedwon.com
Certified Developer | Certified Advanced Administrator
Blog: GlynATheApexGuy@blogspot.com
Twitter: @GlynAtClosedWon

All Answers

Sandeep001Sandeep001
What is the reason to execute trigger class asynchronously? Is there any web service callout made in the trigger class?
GlynAGlynA
You are right that the trigger will complete, the DML will complete, the AJAX will complete and the page will be rerendered all before the @future method in the "oppClose" class executes.  This must be by design for some reason.  Web callouts is one reason, increased CPU execution time is another.

One thing I've noticed, though, is that this trigger is not bulk-safe.  It will work well with one (or a small number) of records, but you can only launch 10 @future methods per transaction.  If the trigger calls "oppClose.cloneOpp()" more than 10 times, the trigger will fail with an uncatchable exception.

The code in the next post is a refactor of the trigger that makes it bulk-safe.  You will need to modify both "oppClose.createCase" and "oppClose.cloneOpp" so that they take a set of IDs and create/clone multiple records.  I hope this is useful.

Glyn Anderson
Sr Developer | System Analyst | ClosedWon | closedwon.com
Certified Developer | Certified Advanced Administrator
Blog: GlynATheApexGuy@blogspot.com
Twitter: @GlynAtClosedWon
This was selected as the best answer
GlynAGlynA
<pre>
trigger Opp on Opportunity ( after update )
{
    Set<String> set_Statuses = new Set<String>{ 'Completed', 'Non-renewable', 'Exception' };

    Set<Id>             set_OppsToProcess   = new Set<Id>();
    Set<Id>             set_OppsToClone     = new Set<Id>();
    List<Opportunity>   list_OppsToUpdate   = new List<Opportunity>();

    for ( Opportunity newOpp : trigger.new )
    {
        Opportunity oldOpp = Trigger.oldMap.get( newOpp.Id );

        if ( newOpp.Probability != 100 || oldOpp.Probability == 100 ) continue;

        set_OppsToProcess.add( newOpp.Id );
        if ( !set_Statuses.contains( newOpp.Clone_Status__c ) )
        {
            set_OppsToClone( newOpp.Id );
            list_OppsToUpdate.add
            (   new Opportunity
                (   Id              = newOpp.Id,
                    Clone_Status__c = 'Completed'
                )
            );
        }
    }

    oppClose.createCases( set_OppsToProcess, false );
    oppClose.cloneOpps( set_OppsToClone );
    update list_OppsToUpdate;
}
</pre>
MC2014MC2014
Yes, it seems that execution time may be the reason why it was asyncronized as oppose to using it with a webservice.