Edit 2:
Client Library: After reviewing it is not easily suggested that this is for the .NET client library.
DLL: Google.Apis.Admin.email_migration_v2.dll
What steps will reproduce the problem?
Generate a process which contains a Google.Apis.Admin.email_migration_v2.AdminService instance for each unique Google Apps Gmail mailbox that will have messages sent to it. All of the AdminService objects generated use the same OAuth2.0 credentials and application name. Each AdminService object generated will only send messages to one Google Apps user’s mailbox. For example, if we were sending messages to five different Google Apps Gmail mailboxes we would generate five AdminService objects to send messages; one for each user’s mailbox.
Biggest thing to note is that each AdminService object created is created on a separate process.
AdminService objects were given a FileDataStore object to change the location of where the refresh token is stored; C:\ProgramData\SomeFile\SomeFile.
Supplied appropriate scopes to the credentials.
Begin sending mail messages on each process. Using one thread to send messages in each process, so only one message is sent at a time to each user’s mailbox.
Each message sent gets its own instance of MailItem and MailResource.InsetMedia
The MailResource.InsertMedia object is generated for each item by calling AdminService.Mail.Insert(MailItem, string, Stream, string) method.
When our code makes the call to MailResource.InsertMediaUpload.UploadAsync(CancellationTokenSource).Result is where we can receive the error.
- The error is caught and handled (logged) from the return type of the aforementioned call; the type is Google.Apis.Upload.IUploadProgress. The exception is handled using the IUploadProgress.Exception property.
What is the expected output? What do you see instead?
The expected output would be a successful message response or the exception property of the IUploadProgress to be null after the return of the task. Instead we are receiving the following error message:
The service admin has thrown an exception: Google.GoogleApiException:Google.Apis.Requests.RequestError
Limit reached. [412] Errors [Message[Limit reached.] Location[If-Match - header] Reason[conditionNotMet] Domain[global]]
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
at Google.Apis.Upload.ResumableUpload`1.d__e.MoveNext()
What version of the product are you using?
- Google.Apis.Admin.Email_Migration_v2 (1.8.1.20)
What is your operating system?
- Windows Server 2008 R2 Enterprise (SP1)
What is your IDE?
- Visual Studio 2013 Premium
What is the .NET framework version?
- 4.0.30319
Please provide any additional information below.
Non-consecutive messages can fail (with the 412 http status code provided above) during the process of sending the messages. Once we receive this error other messages sent after the failed message(s) can succeed. (Items can fail at any point during the process beginning, middle or end.)
Each message sent has nearly identical content. The size of the messages range from 1KB to 100KB including the size of all associated attachments, not all messages have attachments.
Reprocessing the failed items at a later time results in successful message responses and the appropriate items are sent to the user’s Google Apps Gmail Inbox.
The maximum number of Google Apps user’s mailboxes sent to at one time was ten.
After checking the quotas of our Google Developers Console project:
We were nowhere near the specified limit of 20 requests a second for the Email Migration API; maxed out at sending 7 requests a second.
Only 2% of the maximum daily requests had been reached.
All messages sent had the same label; the label was well under the 225 character limit. Actually all of the labels/sub-labels applied together only surmounted to 40 characters.
This error message can still be received when sending to only one Google Apps user’s mailbox; only using one process and one thread.
Each process is normally sending anywhere from 1000-5000 messages.
I have not found a lot of specific documentation to explain this particular error in enough detail to remedy the problem at hand.
Questions:
- So what exactly does this 412 http status code mean? What limit is being encountered that this message is referring to?
- Shouldn’t we be receiving some form of 5XX error from the server if we are hitting a limit? In which case wouldn’t the built in exponential back off policy kick in?
- a. Unless the server is checking the POST request for a pre-condition about a server side limit then telling the client to back off which is what a 412 error seems to typically indicate. In that case please give as much detail as possible for question 1.
Sorry for the extensive post! Thanks for your time! I will also be creating a defect/issue in Google's .NET issue tracker and providing a link.
Edit 1:
For anyone interested in following this issue here is a link to the submitted item in Google's issue tracker for .NET. Submitted Issue
For reference it is issue 492.