13

Im trying to build what seemed like a simple SMS messaging application using Twilio's api and running into a few strange momments.

So I have an SMS object that stores the messages and i wrote a simple trigger on there to actually call the code that sends the message.

Which works for one offs, but if i try to create a bunch of sms messages all at once i get an error saying i cant do more then 10 @future calls at once, and sadly because of the way twilio works each sms message has to be its own callout.

So i assume the answer is to batch the @future calls? but is there a way to have a trigger start a batch job??

10

Yes, you can start a batch from a trigger, but I would advise against it. From the documentation:

Use extreme care if you are planning to invoke a batch job from a trigger. You must be able to guarantee that the trigger will not add more batch jobs than the five that are allowed. In particular, consider API bulk updates, import wizards, mass record changes through the user interface, and all cases where more than one record can be updated at a time.

A better solution would be to have a status on the SMS object and then have a scheduled job that then executes a batch for you.

  • 1
    I believe that you can call out 10 times per future invocation, so the trigger could work on up to 100 records. I would use a fallback option to batch delivery if there are more than 100 in a batch. And as far as that goes, I'd rather suggest that they use the scheduler interface instead of a straight batch (has a limit of 100 instead of 10), but this answer is spot on. – sfdcfox Aug 19 '13 at 22:17
  • I see.. so your recommending that messages arent send automatically but only when the batch job finds them and sends them. That makes sense? Are there similar limits on how often a batch can be run? Could i have the scheduled task run every hour? – Keith Mancuso Aug 19 '13 at 23:02
  • Random other thought, and its not ideal but right now i have a workflow rule that checks a checkbox which in turn is what calls the trigger. What if the checkboxes were checked using a time dependent workflow action instead? would that get around the limits since each action would be its own call? – Keith Mancuso Aug 20 '13 at 0:01
  • Your biggest challenge is that you can only have 5 batches active at one time. You can schedule a job to run and kick off the batch as often as you'd like as long as you don't have 5 other batches in process. – Daniel Hoechst Aug 20 '13 at 0:16
  • As for the time-based workflow idea, I think those can also get batched, so you may still run into limits. – Daniel Hoechst Aug 20 '13 at 0:16
2

The thing about future methods is that, being decoupled from the current thread, you cannot pass anything that is passed by reference.

You don't share your code, but what you probably need to do is create the records in this custom object as part of your trigger code. Let's say, for example, you were writing a trigger for accounts:

List<msg_obj__c> newmsgs = new List<msg_obj__c>();

for (Account a: Trigger.new) {
  ...code to create msg_obj__c records...
  msg_obj__c mo = new msg_obj__c();
  newmsgs.add(mo);
}

insert newmsgs; 

Once you complete this, then pass all the IDs of the new message records into a single future call:

Map<Id,msg_obj__c> msgMap = new Map<Id,msg_obj__c>(newmsgs);
TwilHelper.sendMessages(msgMap.keyset());

This will make it less likely you will hit the max 10 future invocations per transaction. If you want to be absolutely certain, you can also use the Limits class to test to see if you are nearing the limit and then exit gracefully.

But be careful, there are also limits on future calls per 24 hour period, but you can read more about here in Josh Kaplan's excellent blog about consolidation of asynchronous Apex limits in Summer 13.

  • There's still a max-callout-per-invocation, though. A single future method won't help in the 200 records per trigger scenario. – sfdcfox Aug 19 '13 at 22:19
  • Yes, my initial reading, I missed the statement that Twilio requires a single message delivered on its API. I actually voted up Snr. Hoechst's answer. – pchittum Aug 19 '13 at 22:22
1

You should take a look at Dan Appleman's Advanced Apex book. He describes how to create a custom object for deferred work and have a batch that stays alive, constantly processing this custom object.

You'd have a little more latency than the @Future method, but you can get a new set of governor limits with batch scope of 1--no callout issues there.

We use this approach in my org for a callout scenario that's similar. We're in the process of moving a whole lot of stuff that was in triggers, but wasn't really urgent or easily buto deferred async work.

Sample code here at http://advancedapex.com/dreamforce13/ but definitely get the book

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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