I am going to retrieve all the locations of all accounts using Google My Business Business Information API
, documented Google Business Profile APIs.
I try to write the simplified version of my code below:
Suppose mybusinessaccountLocations
variable is the return type of following function and takes care of authentication and initialising the API.
MyBusinessBusinessInformation mybusinessaccountLocations = initializeMyBusiness(Host);
I have defined a class named accountRecord and locationRecord for managing the related tables in my DB.
ExecutorService ex = Executors.newFixedThreadPool(10);
for (accountRecord rec : accountsList) {
List<locationRecord> LocationsList = Collections.synchronizedList(new ArrayList<>());
ex.execute(new Runnable() {
@Override
public void run() {
String readMask = "storeCode,regularHours,name,languageCode,title,phoneNumbers,categories,storefrontAddress,websiteUri,regularHours,specialHours,serviceArea,labels,adWordsLocationExtensions,latlng,openInfo,metadata,profile,relationshipData,moreHours";
List<Location> locations = Collections.synchronizedList(new ArrayList<>());
String accountName = rec.getName();
try {
MyBusinessBusinessInformation.Accounts.Locations.List locationsList = mybusinessaccountLocations
.accounts().locations().list(accountName).setReadMask(readMask);
ListLocationsResponse Response = locationsList.execute();
locations = Response.getLocations();
System.out.println("Response Size ="+ Response.size());
while (Response.getNextPageToken() != null && Response != null && !Response.isEmpty()) {
locationsList.setPageToken(Response.getNextPageToken());
Response = locationsList.execute();
if (Response != null && Response.getLocations() != null) {
locations.addAll(Response.getLocations());
}
}
}
catch (Throwable t) {
throw new RuntimeException("\n\n Throwable occurred: " + t.getMessage(), t);
}
if (locations != null && !locations.isEmpty()) {
// processing the locations and saving in DB
.
.
.
}
}
});
}
ex.shutdown();
while (!ex.isTerminated()) {
}
Since, I am using ExecutorService
, sometimes it exceeds the time_limit defined by google (Quota), or there are server_side errors such as
{
"code" : 503,
"errors" : [ {
"domain" : "global",
"message" : "The service is currently unavailable.",
"reason" : "backendError"
} ],
"message" : "The service is currently unavailable.",
"status" : "UNAVAILABLE"
}
I need the code wait some milliseconds up until there is no more such errors and retry the exact request without skipping any pagination or account.
I tried to use AtomicInteger
and
synchronized(i) {
if( i.getAndIncrement() >= 50 ) {
Thread.sleep(20000);
i.set(0);
}
}
However, this is not a very efficient method, I have heard Exponential Backoff would be more efficient, but I do not know how to implement. I would appreciate any help.
There are RateLimiter implementations that exist already (https://guava.dev/releases/19.0/api/docs/index.html?com/google/common/util/concurrent/RateLimiter.html). As for the retry/backoff logic, it might depend on your framework if you can reuse existing implementations (e.g. https://www.baeldung.com/spring-retry).