9

我有一个Google Apps脚本,我循环通过我的谷歌Analytics帐户,直到我去 一定的个人资料。
if (profileItems[i].getName() == "Dev Test")
比另一个功能(参见下文),我打这个电话给谷歌Analytics(分析)API,并始终得到异常抛出:异常:配额错误:用户速率超限

异常:配额错误:用户速率超限

function getReportDataForProfile(profileId) { 
var tableId = 'ga:' + profileId; 
var startDate = getLastNdays(14); // 2 weeks (a fortnight) ago. 
var endDate = getLastNdays(0);  // Today. 

var optArgs = { 
    'dimensions': 'ga:keyword',    // Comma separated list of dimensions. 
    'sort': '-ga:visits,ga:keyword',   // Sort by visits descending, then keyword. 
    'segment': 'dynamic::ga:isMobile==Yes', // Process only mobile traffic. 
    'filters': 'ga:source==google',   // Display only google traffic. 
    'start-index': '1', 
    'max-results': '250'      // Display the first 250 results. 
}; 

// 
//Exponential Backoff 
// 
for (var n=0; n<6; n++) { 
try { 
    var results = Analytics.Data.Ga.get(
    tableId,     // Table id (format ga:xxxxxx). 
    startDate,    // Start-date (format yyyy-MM-dd). 
    endDate,     // End-date (format yyyy-MM-dd). 
    'ga:visits,ga:pageviews', // Comma seperated list of metrics. 
    optArgs); 
} catch(e) { 
    if (n == 5) { 
    //var results = e; 
    //throw new Error('Quota ERROR'); 
    throw (e) 
    } 
    Utilities.sleep((Math.pow(2,n)*1000) + (Math.round(Math.random() * 1000))); 
    }  
} 
return results; 
} 
  • 我将API控制台中的每用户限制的数量增加到10.0
  • 使用的Porcentage是6%
  • 我申请指数退避
  • 我也相信,只是要求在访问次数和浏览量我不 exagerating我的呼叫数。

The full code

任何ideias是怎么回事?

回答

2

这确实是因为你不能查询每秒超过10个请求。我在这里张贴的解决方案(即使这是一个老问题),因为它可以帮助别人:

/** 
* CallLimiter 
* @param {Number} numberOfCalls how many calls per duration are we allowed to do 
* @param {Number} duration  duration in ms 
*/ 
function CallLimiter(numberOfCalls, duration){ 
    var lastCall = 0; 
    var tokens = 0; 

    return function limiter(f){ 
    var now = +new Date(); 

    if (now - lastCall > duration) { 
     tokens = numberOfCalls; 
    } 

    if (tokens <= 0) { 
     tokens = numberOfCalls; 
     // wait for `duration` before calling limiter(f) again 
     return setTimeout(limiter.bind(this, f), duration); 
    } 

    tokens--; 
    lastCall = now; 
    f(); 
    }; 
} 

这里是如何使用它:

// Stub... 
var Analytics = {Data: {Ga:{get:function(cb){ 
     cb(); 
}}}}; 

function app(){ 
    // Wrap the api call inside a limiter 
    limiter(function(){ 

    Analytics.Data.Ga.get(function(err, data){ 
     // do something with the data... 

     // ... then, loop if necessary 
     app(); 
    }); 

    }); 
} 

// Start 
app(); 

这里是一个阻塞斯卡拉版:

class CallLimiter(rate: Throttler.Rate) { 
    var lastCall  = 0 
    var duration  = rate.duration.toMillis 
    var current_tokens = 0 

    def apply[A](f:() => A): A = { 
    val d = new Date().getTime 

    if (d - lastCall > duration) { 
     current_tokens = rate.numberOfCalls 
    } 
    if (current_tokens <= 0) { 
     // wait for `duration` before calling f() 
     Thread.sleep(duration) 
     current_tokens = rate.numberOfCalls 
    } 
    current_tokens = current_tokens - 1 
    lastCall = d 
    f() 
    } 
} 

用法:

import akka.contrib.throttle.Throttler 

val limiter = new CallLimiter(new Rate(10, Duration(1, TimeUnit.SECONDS))) 
val accounts = limiter(() => analytics.management().accounts().list().execute().getItems) 
+0

你的解决方案是好的,但如果我有20个电话等待的10个呼叫限制,你的关键部分与他们同时被释放结束,命中率限制。 – 2015-09-07 08:28:49