Error in post-install HTTP request

I’m developing a package with a post-install script.
The script makes a HTTP request to my webserver, or sends me an email if an error occured.

Every time the script is run, I receive this error:

System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out

Here’s the script. I have tried deleting the “sendEmail” method, thinking that it may be the problem. The problem is that without it I don’t really have a way to know what went wrong (and the request still isn’t made):

@isTest
public class PiplInstallationNotify implements InstallHandler {

        public static void onInstall(InstallContext ctx){
        try {
            User activeUser = [Select Email From User where Id = : ctx.installerId() limit 1];
            String userEmail = activeUser.Email;
            String orgId = ctx.organizationId();

            HttpRequest req = new HttpRequest();
            HttpResponse res = new HttpResponse();
            Http http = new Http();

            req.setEndpoint(MY_SERVER);
            req.setMethod('POST');

            //these parts of the POST you may want to customize
            req.setCompressed(false);
            req.setBody('email='+userEmail+'&organization_id='+orgId);
            req.setHeader('Content-Type', 'application/x-www-form-urlencoded');  
            res = http.send(req);
            try {
                sendEmail(res.getBody());
            } catch(System.CalloutException e) {
                System.debug('Callout error: '+ e);
                sendEmail('Callout error: '+ e);
            }
            System.debug(res.getBody());
        } catch(Exception ex){
           sendEmail('Message : ' + ex.getMessage() + 'Line no : ' + ex.getLineNumber() + ' getStackTraceString ' + ex.getStackTraceString() + '' + ex.getCause());
        }
    }

    @future (callout=true)
    public static void sendEmail(String message){
        List<String> listEmailMembers;
        Messaging.SingleEmailMessage emailTobeSent = new Messaging.SingleEmailMessage();
        listEmailMembers = new List<String>();
        listEmailMembers.add(MY_EMAIL);
        emailTobeSent.setToAddresses(listEmailMembers);
        emailTobeSent.setSubject('Email message from Salesforce script');
        emailTobeSent.setHtmlBody(message);
        Messaging.SendEmailResult [] r1 = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {emailTobeSent});
    }

    @isTest
    static void testInstallScript() {
      PiplInstallationNotify postinstall = new PiplInstallationNotify();
      Test.testInstall(postinstall, null);
      Test.testInstall(postinstall, new Version(1,0), true);
      System.assert(true);
    }
}

Answer

InstallHandler context cannot perform any synchronous callouts at all.

https://help.salesforce.com/apex/HTViewHelpDoc?id=apex_post_install_script.htm

It can only perform callouts using an async operation. The callout occurs after the script is run and the install is complete and committed.

If the package install fails, nothing will escape the transaction: no futures, no callouts, no emails. The good news is that any managed released package whose production install fails, for any reason, will automatically send you an error email. It goes to the user selected on the field: Notify on Apex Error.

Attribution
Source : Link , Question Author : Josh Liberty , Answer Author : Matt and Neil

Leave a Comment