4

Scenario:

  1. After an object is inserted/updated (can happen after any of the two) - I update an external system with that object's info - Object ID is needed - which is why I need the After Insert.
  2. Once I get from the trigger (FutureHandler) the result from the Httprequest - I parse it to check for error codes.
  3. If all is ok, I need to update the object with a boolean checkbox: True/False - IsObjectTransmitted - I can't update the object at this time.

    3.1 Else - Need to roll back the entire Trigger.

How can I achieve that?

3 Answers 3

3

You can NOT avoid the record insertion/update, but you could do something this:

@future
public void externalValidation(Sobject newObject, SObject oldObject){

    //callout code sending the newObject
    //then, retrieve the current object from db ()
    SObject o = [Select id, IsObjectTransmitted from YOUROBJECT where id=:sentId];
    if(response.getStatusCode() == 200){ //or other condition you need to know if all was Ok 
       o.IsObjectTransmitted = true;
    }else{
       if(oldObject == null){ //was an insert
         delete o;
       }else{
         //probably need to do this to avoid the trigger call. 
         // or any other technique to control the trigger call.  
         oldObject.avoidTrigger__c = true; 

         update oldObject;
       }
    }
}

Colateral damage

If you have other related DML into the update/insert trigger you should rollback those changes by triggering the reverse logic on delete trigger or update(detecting using a flag that is a rollback)

4
  • 1
    Good answer, in essence, the future method needs access through its arguments to all information to perform a manual rollback. This can be very hard to do depending on the number of chained triggers and the problem is only compounded if workflows run and do email alerts (no way to recall those emails) or outbound messages (same) or approval processes start (might need to do a recall). Better to have a design that can tolerate the failure to update the external system and allow for retry (automatic or manual)
    – cropredy
    Commented Mar 27, 2014 at 6:10
  • Totally agreed. To revert a complete async operation is always the harder part. But this sample worked for me on simple external validations. Commented Mar 27, 2014 at 7:44
  • Thanks for the answer: but don't I trigger the after update again in your Else/Else option?
    – Saariko
    Commented Mar 30, 2014 at 7:12
  • @Saariko yes it does. But as I mentioned, you could avoid that using a flag, for instance: oldObject.avoidTrigger__c=true; update oldObject; or some way to avoid it. Commented Mar 30, 2014 at 9:35
2

Because you are using an @future which is a separate transaction from your original transaction (insert/update) you cannot simply roll it back by giving the record and error.

Suggestions:

  • What you can do if you'd like for update is depending on how many fields you are rolling back, is set up field level tracking and using the history table, update date the record with the prior value if it was changed.
  • If this is an insert, you just flag this record with a custom field so it can be reprocessed if you'd like or delete it.
1

the transaction boundaries are tightly coupled and savepoint, rollback and commit are all happening in a single context. In your transaction the callout handled outside the context of trigger and in salesforce considered to be a separate transaction and not related to the one happening inside the trigger. Since you have the record id it is better to initiate a delete.

1
  • Thanks. If it's an after update, I can't delete the object (updated question)
    – Saariko
    Commented Mar 26, 2014 at 14:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .