Calendar usage limits exceeded - unrelated to 10,000 requests/day and (seemingly) unrelated to user requests/second/user limits

2,691 views
Skip to first unread message

Heather Havel

unread,
Mar 22, 2013, 5:57:51 PM3/22/13
to google-ca...@googlegroups.com
We create and populate a number of Google calendars via their Calendar API for each semester.  However, we are now getting a 403 "Calendar usage limits exceeded" error even though our daily quota shows only 4%.

I am using Version 3 code, TwoLeggedOAuthCredentials and the program is an authorized registered client (IOW: the calendars are created on behalf of multiple accounts.)

Last successful run: March 12th (191 Google requests)
Last successful large imports: 2013-01-11, 9975 Google requests, 2013-01-21, 4929 Google requests & 2013-01-22, 1103 Google requests

At about 4% of our quota (https://code.google.com/apis/console/b/0/#project:1077083635926:quotas) the program starts getting the following error: <HttpError 403 when requesting https://www.googleapis.com/calendar/v3/calendars?alt=json returned "Calendar usage limits exceeded.">

If the program is re-run after a time (15 minutes +) it will run a couple more requests before receiving the same error.  The calendar information it errored on previously will succeed if re-run after a "cool-off" period.  The code itself sleeps for the number of times it receives that error multiplied by 20 seconds and tries ten times (waits 20 seconds after the first error, forty seconds after the second error) but it has increased the time to run the program greatly.

I increased the per user limit from 5 requests/second/user to 10.0 requests/second/user yesterday.   So far this has had no noticeable change in behavior.  Stepping through the code slowly also doesn't seem to have impact, leading me to believe it is unrelated to the requests per second.

Is this a bug or a feature that I haven't found the documentation for yet?

Thank you in advance,

Heather Havel

lubos....@szscb.cz

unread,
Mar 27, 2013, 1:29:43 PM3/27/13
to google-ca...@googlegroups.com
I'm having the same issue. While syncing our school timetables (totaly 1000+ events) using Google Calendar API V3 and Java Client I'm getting "Error Message: Calendar usage limits exceeded.". I add events by batch import. It seems some events are succesfully added but most of them not.

Can someone help?

Lubos Palisek

Dne pátek, 22. března 2013 22:57:51 UTC+1 Heather Havel napsal(a):

Heather Havel

unread,
Mar 27, 2013, 2:33:54 PM3/27/13
to google-ca...@googlegroups.com
So what I did was I try each call to Google 10 times - and between each attempt at a call the program "sleeps" for 40 seconds more.  So after the first attempt the program sleeps 40 seconds, after the second attempt it sleeps 80 seconds, the third 120 seconds and so forth.  I do not yet know where the perfect wait time is (glancing through logs it looks to be between 15 minutes and a half hour - so you could try sleeping 900 seconds after the first try instead.) 

I did more research on the cause and it looks like Google put quotas on event and calendar creation per ACCOUNT per time period.

HTH,

Heather Havel

unlimit

unread,
Apr 4, 2013, 10:29:26 AM4/4/13
to google-ca...@googlegroups.com
We have faced with the same issue. But in our case we are using Import API for inserting new events. We created post on SO - http://stackoverflow.com/questions/15473732/google-calendar-api-calendar-usage-limits-exceeded

We tried to remove all attendees for importing events, but this didn't help!

Can someone provide more information about 'Usage limits'?

Aleksandr Vinokurov

unread,
Apr 7, 2013, 3:13:32 PM4/7/13
to google-ca...@googlegroups.com
Just have had the same issue.

Was needed to insert about 300 calendars, started receiving 403-s after 24 calendar insert API call.

But a week ago I have inserted in burst about 190 events to one calendar without any error...

Would be appreciated for the reply from Google Cal team...
-- Aleksandr

Heather Havel

unread,
Apr 8, 2013, 4:59:59 PM4/8/13
to google-ca...@googlegroups.com
I have a reply in on unlimit's StackOverflow question. 

Additionally, last week I filled out a quota increase form request on the API dashboard.  I filled out the request late last week, so I plan on waiting until next Wednesday before following up with our Google Apps for Higher Education contact.  I'll update this thread if I hear any additional information.

Howard Smith

unread,
Apr 12, 2013, 6:13:30 PM4/12/13
to google-ca...@googlegroups.com
Heather, I read all of your posts in this topic, but I'm wondering if you really throw a lot of data at Google Calendar. I ask, because I know I throw a lot of data at Google Calendar, but only at 'one' google calendar, and the google calendar is updated throughout the day as endusers use my web app.

My data is not that large (per event), but when it is time to update google calendar from my web app, I get list of events on 'one' date, if any events in the list, then I delete-via-retries (delete all events on that date until no more events exist  on that date), and then I add the possibly-newly-updated events to the calendar for that selected date on the google calendar.

the largest set of data, per event, is the description, of course. the events have (sometimes) quite lengthy URLs as well, and honestly, those URLs have not caused a problem... but recently, I've been getting a 503 error or socket/read timeout error, and honestly, i don't know where to start with that exception (i just finished posting that in a different topic in this google group).

So/again, i'm just wondering how much data you are pushing to and/or storing in google calendar. I know that i'm pushing and storing a lot of data on google calendar...if you only knew. :)

Howard Smith

unread,
Apr 12, 2013, 6:19:32 PM4/12/13
to google-ca...@googlegroups.com
Heather,

5 seconds delay every 2 or 3 'requests' works perfectly for me. After tweaking my implementation/usage of google calendar API for the last 9 to 12 months, I finally decided to go with that implementation plus,

1. delete-events-on-a-single-day-until-no-more-events-exist-on-that-day
2. add events to that (single/selected) day/date

That resolved the 'duplicate events' issue that i have been dealing with, every now and then, when dates have more events. Evidently, I was hitting a usage limit, I forgot what it is, but 5 requests per some # of seconds.

Also, i had to tighten up my code via @Singleton bean to control access of certain methods and write code that would not allow any 'concurrent' access/requests to the google calendar (API).

Howard

Howard Smith

unread,
Apr 12, 2013, 6:27:34 PM4/12/13
to google-ca...@googlegroups.com
Please see/read below, and scroll down...sharing my code below. :)


On Friday, April 12, 2013 6:19:32 PM UTC-4, Howard Smith wrote:
Heather,

5 seconds delay every 2 or 3 'requests' works perfectly for me. After tweaking my implementation/usage of google calendar API for the last 9 to 12 months, I finally decided to go with that implementation plus,

1. delete-events-on-a-single-day-until-no-more-events-exist-on-that-day
2. add events to that (single/selected) day/date

That resolved the 'duplicate events' issue that i have been dealing with, every now and then, when dates have more events. Evidently, I was hitting a usage limit, I forgot what it is, but 5 requests per some # of seconds.

Also, i had to tighten up my code via @Singleton bean to control access of certain methods and write code that would not allow any 'concurrent' access/requests to the google calendar (API).

Howard


Look for the 'delay...' method below, and how often it is called before 'every' google calendar API call/method. My delete events method skips all-day events except for the events that begin on or within the selected date (range).


    private void addEventToCalendar(GoogleCalendarEvent eventToAdd) throws Exception {
        try {

            Event event = new Event();
            event.setSummary(eventToAdd.getSummary());
            event.setDescription(eventToAdd.getDescription());
            event.setLocation(eventToAdd.getLocation());
            
            DateTime startDateTime = new DateTime(eventToAdd.getStart(), TimeZone.getTimeZone("UTC"));
            event.setStart(new EventDateTime().setDateTime(startDateTime));
            
            DateTime endDateTime = new DateTime(eventToAdd.getEnd(), TimeZone.getTimeZone("UTC"));
            event.setEnd(new EventDateTime().setDateTime(endDateTime));
            
            oAuthRequestAccess();
            delayIfNecessaryAndUpdateCounter();
            client.events().insert(calendarEntry.getId(), event).execute();

        } catch (GoogleJsonResponseException googleJsonException) {
            addEventToLog(eventToAdd);
            String msg = "caught the following exception: " +
                         googleJsonException.getDetails().toPrettyString();
            logger.info(msg);
            throw googleJsonException;
        } catch (Exception e) {
            addEventToLog(eventToAdd);
            String msg = "caught the following exception: " +
                         (e.getMessage() != null ? e.getMessage() : e.getLocalizedMessage());
            logger.info(msg);
            throw e;
        }
    }
    
    private void addEventToLog(GoogleCalendarEvent event) {
        String description = (event.getDescription() != null ? event.getDescription() : "null"),
               location = (event.getLocation() != null ? event.getLocation() : "null"),
               log,
               summary = (event.getSummary() != null ? event.getSummary() : "null");
        log = "Start: " + (new org.joda.time.DateTime(event.getStart())).toString("MM/dd/yyyy") +
              "; End: " + (new org.joda.time.DateTime(event.getEnd())).toString("MM/dd/yyyy") +
              "\nSummary: " + summary +
              "\nLocation: " + location +
              "\nDescription: " + description;
        logger.info(log);
    }
    
    /*
     * As quoted/listed on Google API console, https://code.google.com/apis/console/
     * 
     * Calendar API
     * 5.0 requests/second/user
     */
    private void delayIfNecessaryAndUpdateCounter() {
        org.joda.time.DateTime dateTime, now;
        now = org.joda.time.DateTime.now();
        if (lastRequest == null ||
            now.isAfter(new org.joda.time.DateTime(lastRequest).plusSeconds(5))) {
            
            apiRequestCounter = 0;
        }
        else if (apiRequestCounter > 3) {
            dateTime = org.joda.time.DateTime.now().plusSeconds(5);
            now = org.joda.time.DateTime.now();
            while (true) {
                if (now.isAfter(dateTime)) {
                    break;
                }
                now = org.joda.time.DateTime.now();
            }
            apiRequestCounter = 0;
        }
        apiRequestCounter += 1;
        lastRequest = new Date();
    }
    
    public void deleteAndAddEvents(Date start, Date end,
                                   List<GoogleCalendarEvent> eventsToAdd) throws Exception {
        deleteEventsViaRetries(start, end);
        for (GoogleCalendarEvent event : eventsToAdd) {
            addEventToCalendar(event);
        }
    }
    
    /*
     * One of the following should meet requirement of delete via retries:
     * 
     * 1. delete events UNTIL NO events deleted (deleteEvents(...) returns false)
     * 2. delete events AT LEAST 3 to 5 times
     */
    public void deleteEventsViaRetries(Date start, Date end) throws Exception {
        // delete events until no events deleted
        while (true) {
            if (!deleteEvents(start, end)) {
                break;
            }
        }
    }
    
    private Boolean deleteEvents(Date start, Date end) throws Exception {
        Boolean eventsDeleted = false;
        try {

            // will be used to only delete events that start on argument start date
            DateTime startDateTime = new DateTime(start, TimeZone.getTimeZone("UTC"));
            DateTime endDateTime = new DateTime(end, TimeZone.getTimeZone("UTC"));
            
            String eventDate, startDate, endDate;
            
            // RFC 3339 date format (e.g. 2011-06-03T10:00:00.000-07:00)
            startDate = startDateTime.toStringRfc3339();
            startDate = startDate.substring(0, 10);
            
            endDate = endDateTime.toStringRfc3339();
            endDate = endDate.substring(0, 10);
            
            Boolean deleteARangeOfDates = true;
            if (startDate.equals(endDate)) {
                deleteARangeOfDates = false;
            }
            
            org.joda.time.DateTime timeMin, timeMax;
            timeMin = new org.joda.time.DateTime(start).withHourOfDay(0).withMinuteOfHour(0);
            if (end != null) {
                timeMax = new org.joda.time.DateTime(end).withHourOfDay(23).withMinuteOfHour(59);
            }
            else {
                timeMax = new org.joda.time.DateTime(start).withHourOfDay(23).withMinuteOfHour(59);
            }
            
            oAuthRequestAccess();
            delayIfNecessaryAndUpdateCounter();
            Events events = client.events().list(calendarEntry.getId())
                            .setTimeMin(new DateTime(timeMin.toDate(), TimeZone.getTimeZone("UTC")))
                            .setTimeMax(new DateTime(timeMax.toDate(), TimeZone.getTimeZone("UTC")))
                            .execute();
            //logger.info("GoogleCalendarUtil.updateEventsOnSingleDate(): existing EVENTS to delete = " + events.getItems().size());
            if (events.getItems() != null && !events.getItems().isEmpty()) {
                while (true) {
                    for (Event event : events.getItems()) {
                        eventDate = event.getStart().getDateTime().toStringRfc3339();
                        eventDate = eventDate.substring(0, 10);
                        /*
                         * 1. when NOT deleting a range of dates, then only delete events
                         *    that start on argument start date
                         * 2. when deleting a range of dates, then only delete events
                         *    that start on or after argument start date
                         */
                        if (deleteARangeOfDates) {
                            if (eventDate.compareTo(startDate) >= 0) {
                                delayIfNecessaryAndUpdateCounter();
                                client.events().delete(calendarEntry.getId(), event.getId()).execute();
                                eventsDeleted = true;
                            }
                        }
                        else {
                            if (startDate.equals(eventDate)) {
                                delayIfNecessaryAndUpdateCounter();
                                client.events().delete(calendarEntry.getId(), event.getId()).execute();
                                eventsDeleted = true;
                            }
                        }
                    }
                    String pageToken = events.getNextPageToken();
                    if (pageToken != null && !pageToken.isEmpty()) {
                        delayIfNecessaryAndUpdateCounter();
                        events = client.events().list(calendarEntry.getId()).setPageToken(pageToken).execute();
                    } else {
                        break;
                    }
                }
            }
            
        } catch (GoogleJsonResponseException googleJsonException) {
            String msg = "GoogleCalendarUtil.deleteEvents(): " +
                         googleJsonException.getDetails().toPrettyString();
            logger.info(msg);
            throw googleJsonException;
        } catch (Exception e) {
            String msg = "GoogleCalendarUtil.deleteEvents(): " + e.getMessage();
            logger.info(msg);
            throw e;
        } finally {
            // cleanup
        }
        return eventsDeleted;
    }



Reply all
Reply to author
Forward
0 new messages