Skip to content

sdk中引用的bot-monitor有bug,导致数据统计功能根本就没有执行过。 #15

@gsnable

Description

@gsnable

详见https://dueros.baidu.com/forum/topic/show/307433

技能之所以能够对数据统计是因为web服务在将response返回给音箱之前,把response也发给了百度数据统计服务器。见BaseBot源代码中的run方法。

public String run() throws Exception {
// 请求参数不合法
if (verify() == false) {
return this.illegalRequest();
}

this.dispatch();
String responseStr = this.build(response);
this.botMonitor.setResponse(responseStr);//将response注入
this.botMonitor.uploadData();//提交给统计服务器
return responseStr;
}

我开始以为uploadData()方法出了问题,后来发现第一个问题出现在setResponse里。见BotMonitor的setResponse方法。

public void setResponse(String responseData) {
if (StringUtils.isBlank(responseData)|| this.isShouldDisable()) {
return;
}

this.requestEndTime = this.getMillisecond();
this.response = new Response(responseData);
}

这个本该为monitor中response属性赋值的方法执行后,response总是为空,因为isShouldDisable()只会返回true,具体说是this.response == null这个条件永远是true。

public boolean isShouldDisable() {
if (StringUtils.isBlank(this.privateKey)
|| this.request == null
|| this.response == null
|| !this.enabled) {
return true;
}
return false;
}

monitor从BaseBot构造方法创建后response默认为空,除了setResponse方法没有其他地方赋值。setResponse方法中的赋值语句却因为调用isShouldDisable返回true,永远没有机会执行。参照nodejs和python中的isShouldDisable方法,你会发现只有Java版的isShouldDisable方法增加了request和response两个条件。

nodejs版

isShouldDisable() {
if (this._privateKey == null || this._privateKey.length === 0
|| !Number.isInteger(this._environment) || !this._enabled) {
return true;
}
return false;
}

python版

def is_should_disable(self):
'''
判断Monitor是否可用
:return:
'''
if not self.enabled:
logging.warning('未开启数据统计功能, 如果使用统计功能需要调用set_monitor_enabled(True)')
return True
if self.enabled:
if not self.private_key or len(self.private_key) == 0:
logging.warning('未配置私钥, 请调用set_environment_info(prikey)')
return True
return False

这两个isShouldDisable方法只检查privateKey和enabled,nodejs还检查了environment,但二者均没有检查request和response。显然,检查request和response应该放在uploadData方法中,而不是这里。

注释掉这两个判断条件,果然monitor的response有值了,uploadData也执行了,但是依然没有统计数据。

uploadData方法片段

httpClient.execute(httpPost, new FutureCallback() {
@OverRide
public void completed(HttpResponse result) {//原文这里就是result,很奇特。
}

@OverRide
public void failed(Exception ex) {
}

@OverRide
public void cancelled() {
}
});

在completed方法中添加调试信息发现,返回结果是“bot pubkey not found.”(通过一个上线但发布新版本的技能访问)或“get bot pub key error.”(通过一个从未上线的技能访问。顺便说下这个问题在论坛也有人问过,结果是无人回复。zeali 发布的 get bot pub key error.)。以上结果是我的environment为0,即调试模式的前提下。我将environment改为1后返回“Failed to verify the signature.”(通过一个上线但发布新版本的技能访问)或“get bot pub key error.”(通过一个从未上线的技能访问。因为截至目前技能上线还没通过,所以不排除上线后能得到正确结果的可能性。

我开始怀疑是公钥私钥不匹配的问题,所以还验证了一下。签名是通过monitor自带的Certificate类的rsaSign方法,验证是网上找的一段方法。结论是公钥和私钥都不能包含第一行和最后一行的说明。bot-sdk-java在示例里强调了这一点,但技能后台配置界面上不论是否去掉收尾两行都不正确。

至此,我认为我能做的已经结束了,虽然知道问题出在数据统计服务器那头,但个人注定是无法解决了。希望sdk开发人员早日解决,提交新版本。

然而,事情却没有结束。隔一段时间我收到短信,告诉我技能稳定性指标不达标。上服务器一看,每次请求都会报异常,too many open files,Failure opening selector createDefault等等。异常指向uploadData方法。

CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
httpClient.start();
HttpPost httpPost = new HttpPost(Config.getUploadUrl());

try {
Map<String, String> contentMap = new HashMap<>();
contentMap.put("data", base64Str);
JSONObject jsonContent = new JSONObject(contentMap);
httpPost.setEntity(new StringEntity(base64Str.toString()));
httpPost.setHeader("SIGNATURE", signRet);
httpPost.setHeader("botId", botId);
httpPost.setHeader("timestamp", timestamp.toString());
httpPost.setHeader("pkversion", pkversion);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

try {
httpClient.execute(httpPost, new FutureCallback() {
@OverRide
public void completed(HttpResponse result) {
}

@OverRide
public void failed(Exception ex) {
}

@OverRide
public void cancelled() {
}
});
} catch (Exception e) {
e.printStackTrace();
}

原因是httpClient大量创建,长期没有关闭,导致资源耗尽。在completed方法里加上close后,这个问题不再出现。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions