5

I am using Google Drive API through pydrive to move files between two google drive accounts. I have been testing with a folder with 16 files. My code always raises an error in the sixth file

"User rate limit exceeded">

I know that there is a limit for the number of request (10/s or 1000/100s), but I have tried the exponential backoff suggested by the Google Drive API to handle this error. Even after 248s it still raises the same error.

Here an example what I am doing

def MoveToFolder(self,files,folder_id,drive):
    total_files = len(files)
    for cont in range(total_files):
        success = False
        n=0
        while not success:
            try:
                drive.auth.service.files().copy(fileId=files[cont]['id'],
                                                body={"parents": [{"kind": "drive#fileLink", "id": folder_id}]}).execute()
                time.sleep(random.randint(0,1000)/1000)
                success = True
            except:
                wait = (2**n) + (random.randint(0,1000)/1000)
                time.sleep(wait)
                success = False
                n += 1

I tried to use "Batching request" to copy the files, but it raises the same errors for 10 files.

def MoveToFolderBatch(self,files,folder_id,drive):
    cont=0
    batch = drive.auth.service.new_batch_http_request()
    for file in files:
        cont+=1
        batch.add(drive.auth.service.files().copy(fileId=file['id'],
                                                 body={"parents": [
                                                     {"kind": "drive#fileLink", "id": folder_id}]}))
    batch.execute()

Does anyone have any tips?

EDIT: According to google support:

Regarding your User rate limit exceeded error, is not at all related to the per-user rate limit set in the console. Instead it is coming from internal Google systems that the Drive API relies on and are most likely to occur when a single account owns all the files within a domain. We don't recommend that a single account owns all the files, and instead have individual users in the domain own the files. For transferring files, you can check this link. Also, please check this link on the recommendations to avoid the error.

Rafael
  • 433
  • 6
  • 12

2 Answers2

2

403: User Rate Limit Exceeded is basically flood protection.

{
 "error": {
  "errors": [
   {
    "domain": "usageLimits",
    "reason": "userRateLimitExceeded",
    "message": "User Rate Limit Exceeded"
   }
  ],
  "code": 403,
  "message": "User Rate Limit Exceeded"
 }
}

You need to slow down. Implementing exponential backoff as you have done is the correct course of action.

Google is not perfect at counting the requests so counting them yourself isn't really going to help. Sometimes you can get away with 15 request a second other times you can only get 7.

You should also remember that you are completing with the other people using the server if there is a lot of load on the server one of your request may take longer while an other may not. Don't run on the hour that's when most people have cron jobs set up to extract.

Note: If you go to google developer console under where you have enabled the drive API got to quota tab click the pencil icon next to

Queries per 100 seconds per user

and

Queries per 100 seconds

You can increase them both. One is User based the other is project based. Each user can make X requests in 100 seconds your project can make Y request per 100 seconds.

enter image description here

Note: No idea how high you can set yours. This is my dev account so it may have some beta access I cant remember.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • Thanks, If I had your quota I would be more the well served! Is this your type of accont? [link](https://support.google.com/googleplay/android-developer/answer/6112435?hl=en) – Rafael Mar 02 '17 at 14:44
  • try and up yours see what happens I cant remember what the max is that you can set it to. – Linda Lawton - DaImTo Mar 02 '17 at 14:44
  • Is this your acc [link](https://support.google.com/googleplay/android-developer/answer/6112435?hl=en). Would this work for web applications? – Rafael Mar 02 '17 at 14:47
  • 1
    Where you registered your app https://console.developers.google.com/ find your project go to library find drive the one you enabled go to the quota tab. API is API I doesn't care what type of project it is – Linda Lawton - DaImTo Mar 02 '17 at 14:49
  • I am using the max for a free acc. I might create an dev acc. Tks – Rafael Mar 02 '17 at 14:53
  • My account is also free :) max from what I can tell by googling is 1000 per user per second and 10000 per project. I contacted google looking for some one to update the page with some info on max – Linda Lawton - DaImTo Mar 02 '17 at 14:56
  • Haven't you paid the $25 registration fee? – Rafael Mar 02 '17 at 15:02
  • Nope only android needs to pay that I am not an android dev – Linda Lawton - DaImTo Mar 02 '17 at 15:04
  • How can I do that? I read that I have to add a billing acc.I have done that, but still I can not increase those numbers. Sorry about all these questions, but I just started with development. – Rafael Mar 02 '17 at 15:39
2

See 403 rate limit after only 1 insert per second and 403 rate limit on insert sometimes succeeds

The key points are:-

  • backoff but do not implement exponential backoff!. This will simply kill your application throughput

  • instead you need to proactively throttle your requests to avoid the 304's from occurring. In my testing I've found that the maximum sustainable throughput is about 1 transaction every 1.5 seconds.

  • batching makes the problem worse because the batch is unpacked before the 304 is raised. Ie. a batch of 10 is interpreted as 10 rapid transactions, not 1.

Try this algorithm

delay=0                              // start with no backoff
while (haveFilesInUploadQueue) {
   sleep(delay)                      // backoff 
   upload(file)                      // try the upload
   if (403 Rate Limit) {             // if rejected with a rate limit
      delay += 2s                    // add 2s to delay to guarantee the next attempt will be OK
   } else {
      removeFileFromQueue(file)      // if not rejected, mark file as done
      if (delay > 0) {               // if we are currently backing off
         delay -= 0.2s               // reduce the backoff delay
      }
   }
}
// You can play with the 2s and 0.2s to optimise throughput. The key is to do all you can to avoid the 403's 

One thing to be aware of is that there was (is?) a bug with Drive that sometimes an upload gets rejected with a 403, but, despite sending the 403, Drive goes ahead and creates the file. The symptom will be duplicated files. So to be extra safe, after a 403 you should somehow check if the file is actually there. Easiest way to do this is use pre-allocated ID's, or to add your own opaque ID to a property.

Community
  • 1
  • 1
pinoyyid
  • 21,499
  • 14
  • 64
  • 115
  • Well, I tried to use 1.5s for each transaction and it worked, but now it is working with 0.1s of delay as well. It might depend on the time I am using the API as @DaImTo said. – Rafael Mar 02 '17 at 19:14
  • 1
    Cool. The 1.5s is not fixed so you can always try to reduce it until you start seeing 304's, then increase it until they stop. I have a JavaScript library which does this. Internally within Google, rate is limited using a bucket/token mechanism. You start with APPROX 25 tokens which you can use as quickly as you like. Once you've sent 25 requests, your bucket is empty and you can't send any more until you have tokens. Tokens are added once every 1.5s. NB. ALL OF THE FIGURES I'VE GIVEN ARE APPROXIMATE AND SUBJECT TO CHANGE SO MUST NOT BE RELIED ON. THEY ARE ONLY GIVEN HERE FOR ILLUSTRATION. – pinoyyid Mar 02 '17 at 19:41
  • I cannot understand this system. It was working until now. Before, I copied 30 files, no problem. Then, I tried again it started to raise the error again. And more, I am trying to copy a folder with 16 files, and the problem is always in the file 7. It copies the first six, but for the seventh it raises the error. – Rafael Mar 02 '17 at 22:19
  • That kinda makes sense. Your first few will normally work OK because your bucket has tokens. Once you deplete the bucket, you get 304'd. The more 304's you get, the more your app is treated as hostile. You simply have to accept the rate limit as a fact of life and slow things down enough to minimise them (but do not exponential backoff). As I said, my library adjusts the delay automatically, and in my experience (uploading 100's of files) it tends to settle down at around one every 1.5s. I'll update my answer with the algorithm I use. – pinoyyid Mar 02 '17 at 23:00
  • I mean 403, not 304 – pinoyyid Mar 02 '17 at 23:13
  • Excellent, I will try your algorithm and come back later. One thing I noticed is that for getting file lists and downloading metadata it seems there is no limit, am I right? – Rafael Mar 02 '17 at 23:33
  • 1
    Don't make any assumptions, but in my experience it's only write transactions that are rate limited. If you think about the massively distributed file system that sits behind Drive, it makes sense that writes are expensive and need to be throttled. – pinoyyid Mar 02 '17 at 23:36
  • I tried to apply for more quota, even though I do not think this is the problem. The google support give me an answer about this 403 error. I will add to my question his comment. – Rafael Mar 03 '17 at 20:02