You need to sign in to do that
Don't have an account?
tonante
How do I avoid a condition where Batch Job indirectly and unknowingly calls the Future method of a trigger's supporting class?
HI I am running a batch class that sets a field on account objects based on a condition and then it loads the account into a list of accounts to be bulk updated. However there is a trigger which fires on Account After Update that interrupts the Bacth job when it tries to do the DML_BEGIN (Update). That trigger takes over and attempts to process the accounts and send the info to Demandware service using a supporting Controller Class that calls a Future Method. Thus this Batch job indirectly calls Future method so I get an exception. We need the batch job to reset the field and update the account and then we want the rest controller having the future method be able to pass this info to the Demandware server account. Thanks for your help.
1) Batch Job class:
1) Batch Job class:
global class BatchCancelMozoFreeTrialObject implements Database.Batchable<sObject> { // global variables global String query; global class UtilException extends Exception {} global database.querylocator start(Database.BatchableContext BC) { // Select All Accounts that have Current as their free trail Status if(query == null) { query = 'Select Id, ' + ' Mozo_Trial_End_Date__c, ' + ' Mozo_Trial_Status__c ' + 'From Account WHERE Mozo_Trial_Status__c = \'Current\' ' + ' And (RecordType.Name like \'%Church%\' Or RecordType.Name like \'%Organization%\')'; } system.debug('<< QUERY >> '+query); return Database.getQueryLocator(query); } global void execute(Database.BatchableContext BC, List<sObject> scope) { List<Account> accountsToUpdate = new List<Account>(); List<ID> storeContactIDs = new List<ID>(); for(sObject s : scope) { Account thisAccount = (Account)s; system.debug('<<DEBUG STATUS >> '+thisAccount.Id+' <<ID>> '+thisAccount.Mozo_Trial_Status__c+'<< DATE >> '+thisAccount.Mozo_Trial_End_Date__c+' VS '+system.today()); if(thisAccount.Mozo_Trial_End_Date__c <= system.today() && thisAccount.Mozo_Trial_Status__c == 'Current') { thisAccount.Mozo_Trial_Status__c = 'Former'; accountsToUpdate.add(thisAccount); } } system.debug(accountsToUpdate); if(accountsToUpdate.size() > 0){ update accountsToUpdate; } } global void finish(Database.BatchableContext BC) { } }2) Trigger which called Controller Method:
trigger updateMozoTrialToDWREAccount on Account (after update) { List<String> accountIds = new List<String>(); List<Account> accountList = new List<Account>(); String doNotCallController = 'success'; RecordType rec = [select Id from RecordType where Name = 'US Organization' limit 1]; User demandwareAppUser = [select Id from User where Name = 'Demandware']; if(Trigger.isUpdate){ system.debug('--------------------'+demandwareAppUser.Id); for(Account accs: Trigger.new){ if(accs.RecordTypeId == rec.Id && accs.LastModifiedById != demandwareAppUser.Id){ system.debug('Account Details'+'--'+accs.Name+'--'+accs.RecordTypeId+'--'+accs.LastModifiedById); accountList.add(accs); } } } for(Integer count = 0; count < accountList.size() ; count++){ if(trigger.old[count].Mozo_Trial_Status__c != trigger.new[count].Mozo_Trial_Status__c || trigger.old[count].Mozo_Free_Trial_ContactID__c != trigger.new[count].Mozo_Free_Trial_ContactID__c || trigger.old[count].Mozo_Trial_Start_Date__c != trigger.new[count].Mozo_Trial_Start_Date__c || trigger.old[count].Mozo_Trial_End_Date__c != trigger.new[count].Mozo_Trial_End_Date__c){ system.debug('--'+trigger.new[count].Id+'--'+trigger.new[count].Mozo_Free_Trial_ContactID__c+'--'+trigger.new[count].Mozo_Trial_Status__c+'--'+trigger.new[count].Mozo_Trial_Start_Date__c+'--'+trigger.new[count].Mozo_Trial_End_Date__c); //DemandwareController.getAccessToken(trigger.new[count].Id,trigger.new[count].Mozo_Free_Trial_ContactID__c,trigger.new[count].Mozo_Trial_Status__c,trigger.new[count].Mozo_Trial_Start_Date__c,trigger.new[count].Mozo_Trial_End_Date__c); if( trigger.old[count].Mozo_Trial_Status__c == 'Former' && trigger.old[count].Mozo_Trial_End_Date__c == trigger.new[count].Mozo_Trial_End_Date__c && (trigger.new[count].LastModifiedById == '00550000000vuyG' || trigger.new[count].LastModifiedById == '00550000001qiyX')){ doNotCallController = 'fail'; } if(doNotCallController == 'success'){ AccountHelper ah = new AccountHelper(trigger.new[count].Id); accountIds.add(JSON.serialize(ah)); ControllerToUpdateDWREAccount.getAccessToken(accountIds); } } } }3. Controller used by Trigger that has the Future method:
Global class ControllerToUpdateDWREAccount { @future (callout=true) global static void getAccessToken(List<String> accountIds){ //system.debug(accId+' '+MozoTContactId+' '+MozoTStatus+' '+MozoTStartDate+' '+MozoTEndDate); String accErrorId; AccountHelper currIds = null; List<Account> accList = new List<Account>(); //String exceptionString = 'MethodNot'; try{ string accToken=''; Http http = new Http(); HttpRequest req = new HttpRequest(); HttpRequest req1 = new HttpRequest(); HttpRequest reqUpdate = new HttpRequest(); for (String ser : accountIds) { currIDs = (AccountHelper) JSON.deserialize(ser, AccountHelper.class); System.debug('Deserialized in future:'+currIds.Id); accErrorId = currIds.Id; Account a = [SELECT Id,Mozo_Free_Trial_ContactID__c,Mozo_Trial_Status__c,Mozo_Trial_Start_Date__c,Mozo_Trial_End_Date__c FROM Account WHERE id =: currIds.Id]; req.setMethod('POST'); req.setHeader('Authorization','Basic NjQ3NTMxYTktNzZmYy00ZDNhLThjYTMtNmNlNDA5ZmYxMTcxOjcvWFItQSptYWQsRUpNQE5LZD5s'); //req.setHeader('Authorization','Basic 923d2a4c-b33b-4e3c-ad0a-370afbd46abb'); req.setHeader('Content-Type','application/x-www-form-urlencoded'); req.setEndpoint('https://account.demandware.com/dw/oauth2/access_token?grant_type=client_credentials'); HTTPResponse res = http.send(req); JSONParser parser = JSON.createParser(res.getBody()); while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getCurrentName() == 'access_token')) { parser.nextToken(); accToken = parser.getText(); } } system.debug('-----Demandware Access Token-------'+ accToken); if(accToken != null || accToken != ''){ req1.setMethod('GET'); req1.setHeader('Authorization','Bearer ' + accToken); //req1.setEndpoint('https://staging-web-awana.demandware.net/s/-/dw/data/v16_3/custom_objects/Account/0015000000GUZYzAAP'); req1.setEndpoint('https://staging.store.awana.org/s/-/dw/data/v16_3/custom_objects/Account/'+a.Id); HTTPResponse res1 = http.send(req1); system.debug('*******************'+res1.getBody()); string[] headerkeys = res1.getHeaderKeys(); string headerValue; for(string s : headerkeys){ if(s == 'Etag'){ headerValue = res1.getHeader(s); system.debug('header: ' + s + ' value: ' + headerValue); } } if(headerValue != '' || headerValue != null){ reqUpdate.setHeader('Authorization','Bearer ' + accToken); reqUpdate.setHeader('Content-Type','application/json; charset=UTF-8'); reqUpdate.setHeader('If-Match',headerValue); Map<String,object> jsonObject = new Map<String,object>(); //jsonObject.put('c_MozoTrialStatus','Current'); jsonObject.put('c_MozoTrialStatus', a.Mozo_Trial_Status__c); jsonObject.put('c_MozoTrialContactID', a.Mozo_Free_Trial_ContactID__c); Integer d = a.Mozo_Trial_Start_Date__c.day(); Integer mo = a.Mozo_Trial_Start_Date__c.month(); Integer yr = a.Mozo_Trial_Start_Date__c.year(); DateTime ST = DateTime.newInstance(yr, mo, d, 12, 0, 0); jsonObject.put('c_MozoTrialStartDate', ST); Integer ed = a.Mozo_Trial_End_Date__c.day(); Integer emo = a.Mozo_Trial_End_Date__c.month(); Integer eyr = a.Mozo_Trial_End_Date__c.year(); DateTime ET = DateTime.newInstance(eyr, emo, ed, 12, 0, 0); jsonObject.put('c_MozoTrialEndDate', ET); String JSONString = JSON.serialize(jsonObject); reqUpdate.setBody(JSONString); system.debug(JSONString); reqUpdate.setEndpoint('https://staging.store.awana.org/s/-/dw/data/v16_3/custom_objects/Account/'+a.Id); reqUpdate.setMethod('POST'); reqUpdate.setHeader('x-dw-http-method-override','PATCH'); HTTPResponse resUpdate = http.send(reqUpdate); system.debug('*******************'+resUpdate.getBody()); } } }//for }//try outer catch(Exception ne){ system.debug('Exception '+ne); Messaging.SingleEmailMessage mail=new Messaging.SingleEmailMessage(); String[] toAddresses = new String[] {'shaikbaji.a@ecgroup-intl.com'}; mail.setToAddresses(toAddresses); mail.setReplyTo('shaikbaji.a@ecgroup-intl.com'); mail.setSenderDisplayName('Salesforce'); mail.setSubject('Update Failed'); mail.setPlainTextBody('Account Id: '+accErrorId+' not existed in Demandware'); Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail }); accErrorId = null; } } }
All Answers
You can use the System.isBatch() & System.isFuture() method in your use case. These methods will enable you to check if the update is coming from a Batch, if yes, you cn skip calling the future method and alter your logic accordingly.
Refer: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_system.htm
Hope this helps!
Veenesh