I need to Geocode addresses on Account using an HTTP callout; the webservice will only service one address per callout. For this use case it is preferable to geocode the accounts immediately, rather than periodically via a scheduled batch. To do so, I have a class that implements Database.Batchable
and Database.AllowsCallouts
, which takes a list of account ids in the constructor. start()
returns a QueryLocator
for the needed account fields, and execute()
makes the callouts. My trigger (on Account after insert, after update) calls Database.executeBatch()
with a batch size of 10, to stay under the callout limit.
This works perfectly for data loads up to 200 records. Once I get over that size of course, the system splits the records into multiple chunks and invokes the trigger for each chunk (of up to 200 records), so I end up with concurrent executions of my Batchable
class (as each trigger invocation is calling Database.executeBatch()
), and then I get Rate Limit Exceeded errors from my geocoding service provider.
I'm considering changing my trigger logic a bit to query for running/queued batches; if any are found, to use system.scheduleBatch()
instead of Database.executeBatch()
, scaling the minutesFromNow
param based on the number of batches found. Given that scheduled batch delays are guidelines only, this isn't a guarantee that two batches won't run concurrently, but it's possible this could be a 'good enough' solution for my particular case with the right delay param. If not, from there my next option is a separate SObject to track to-be-run batches, and logic in finish()
to run the next batch (perhaps similar to this question, though perhaps without the controlling job).
Before I start complicating things, is there a simple way to prevent multiple instances of a given Batchable class from running concurrently? Or a simpler way of serializing the batches than writing my own scheduler?