Throttled "Directions" request: Tried to make more than 50 requests in 60 seconds swift

50 Views Asked by At

I am trying to implement this https://github.com/nuclearace/SwiftRateLimiter

Here is my code that is calling getDistanceBetweenLocations:

_ = circleQuery?.observe(.keyEntered, with: {(key: String?, location: CLLocation?) in
            mapCoord[key!] = location?.coordinate //stores busID and it's coord in Dictionary
            self.getBusinessData(bus: key!)
            if (!searchBus.contains(key!)){
                searchBus.append(key!)
                
                self.getDistanceBetweenLocations(origLat: coordinates.lat, origLon: coordinates.lon, newLat: mapCoord[key!]!.latitude, newLon: mapCoord[key!]!.longitude, id: key!, done: {distance in
                    busDistance[key!] = distance
                    
                })
            }
        })

And this is the code that is calling the ratelimiter from the GitHub link above:

let GlobalDirectionsRateLimiter = RateLimiter(tokensPerInterval: 50, interval: .minute)
        
        GlobalDirectionsRateLimiter.removeTokens(directionsChecked) {d in
            print(d)
            directions.calculate { (response, error) in
                if let response = response, let route = response.routes.first {
                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "BusDataChanged"), object: nil)
                    done(route.distance/1609)
                } else {
                    print("ERROR getting distance \(String(describing: error))")
                    //busDistance[id] = route.distance/1609
                }
            }
        }

This is the removeTokens()

    public func removeTokens(_ count: Double, callback: @escaping (Double) -> ()) {
        
        if count > bucket.sizeOfBucket {
            callback(-Double.infinity)

            return
        }
        
        let now = Date().timeIntervalSince1970

        if now - intervalStart >= bucket.interval {
            intervalStart = now
            tokensThisInterval = 0
        }

        guard count <= bucket.tokensPerInterval - tokensThisInterval else {
            if firesImmediatly {
                return callback(-Double.infinity)
            }

            queue.asyncAfter(deadline: DispatchTime.now() + ceil(intervalStart + bucket.interval - now)) {
                func afterBucketRemove(tokensRemaining: Double) {
                    self.tokensThisInterval += count

                    callback(tokensRemaining)
                }

                self.bucket.removeTokens(count, callback: afterBucketRemove)
            }

            return
        }

        func afterBucketRemove(tokensRemaining: Double) {
            tokensThisInterval += count

            callback(tokensRemaining)
        }

        return bucket.removeTokens(count, callback: afterBucketRemove)
    }

As I understand this the GlobalDirectionsRateLimiter limits tokensPerInterval to 50 in an interval of 1 minute. I guess my first question is on this line:

GlobalDirectionsRateLimiter.removeTokens(directionsChecked)

In the examples in the readme doc (directionsChecked) is a hard number. I am assuming this is should be a count of doc being checked. Hence my directionsChecked variable which I am increasing by one for each loop. Am I missing something?

1

There are 1 best solutions below

1
hockeyfan530 On

Looks like I fixed this. I defined

let GlobalDirectionsRateLimiter = RateLimiter(tokensPerInterval: 50, interval: .minute)

in a spot where it was redefined each time through the loop. So I defined it once at the top and it seems to be working

Although it's true I no longer get the error I also get my default distance for most of the businesses. If I change to this:

let GlobalDirectionsRateLimiter = RateLimiter(tokensPerInterval: 1, interval: .moreSec) moreSec is 1.25 seconds I get the error on the 51st item but all but 1 of the distances are correct. So the answer isn't quite correct....Still need help