Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

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?

share|improve this question

3 Answers 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)

share|improve this answer
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) –  crop1645 Mar 27 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. –  Martin Borthiry Mar 27 at 7:44
    
Thanks for the answer: but don't I trigger the after update again in your Else/Else option? –  Saariko Mar 30 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. –  Martin Borthiry Mar 30 at 9:35

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.

share|improve this answer
    
Thanks. If it's an after update, I can't delete the object (updated question) –  Saariko Mar 26 at 14:12

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.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.