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.

1

There are 1 answers

1
vpgcloud On BEST ANSWER

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).