2017-02-14 58 views
0

在节点js中,使用'firebase-admin'SDK版本4.1.0,我有一个侦听器,它监听我的数据库中的消息队列引用,处理消息,之后尝试从队列引用中删除它。修改当前引用导致最大堆栈大小超出崩溃

当我在启动脚本之前在队列中有超过一定数量的记录(我的机器上有1354个)时,脚本崩溃时最大调用堆栈超出错误。

奇怪的是,这只发生在脚本启动之前队列中有1354+个值。任何低于此值的问题都会消失。

我不知道这是为什么发生,但我知道它只发生在我尝试修改/删除快照参考对象时。

这里是一个自包含MCVE的问题区域标志着评论:

var admin = require("firebase-admin"); 

var serviceAccount = require("<ADMIN JSON FILE PATH GOES HERE>"); 

admin.initializeApp({ 
    credential: admin.credential.cert(serviceAccount), 
    databaseURL: "<FIREBASE URL GOES HERE>" 
}); 

var ref = admin.database().ref(); 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

// the number of messages to generate for the queue. when this is >= 1354 (on my machine) the program crashes, if it's less than that, 
// it works perfectly fine; your tipping point may vary 
var amount = 1354; 
// message payload to deliver to the queue <amount> times 
var payload = {}; 

// message generation loop 
for (i = 0; i < amount; i++) { 
    var message = {msg: "hello"}; 
    payload['message-queue/' + ref.push().key] = message; 
} 

// add the generated messages simultaneously to message-queue 
ref.update(payload).then(function() { 

    // 'on child added' listener that causes the crash of the program when there are 1354+ pre-existing messages in the queue prior to application start 
    ref.child('message-queue').on('child_added', function(snapshot) { 

     var msgKey = snapshot.key; 
     var msgContents = snapshot.val().msg 

     // do something with msgContents (e.g. sanitize message and deliver to some user's message-received node in the firebase) 

     // ***THIS*** is what causes the crash. if you remove this line of code, the program does not crash. it seems that any 
     // modification/removal to/of the current <msgKey> node does the same 
     ref.child('message-queue').child(msgKey).remove(); 
    }); 
}); 

这里是崩溃的堆栈跟踪:

FIREBASE WARNING: Exception was thrown by user callback. RangeError: Maximum call stack size exceeded 

    at RegExp.exec (native) 
    at RegExp.test (native) 
    at tc (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:63:86) 
    at ub (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:60:136) 
    at vb (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:43:1228) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:44) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 

<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:63 
(d="0"+d),c+=d;return c.toLowerCase()}var zc=/^-?\d{1,10}$/;function tc(a){retur 
n zc.test(a)&&(a=Number(a),-2147483648<=a&&2147483647>=a)?a:null}function Ac(a){ 
try{a()}catch(b){setTimeout(function(){N("Exception was thrown by user callback. 
",b.stack||"");throw b;},Math.floor(0))}}function Bc(a,b,c){Object.definePropert 
y(a,b,{get:c})}function Cc(a,b){var c=setTimeout(a,b);"object"===typeof c&&c.unr 
ef&&c.unref();return c};function Dc(a){var b={},c={},d={},e="";try{var f=a.split 
("."),b=bb(hc(f[0])||""),c=bb(hc(f[1])||""),e=f[2],d=c.d||{};delete c.d}catch(g) 
{}return{wg:b,Ge:c,data:d,mg:e}}function Ec(a){a=Dc(a);var b=a.Ge;return!!a.mg&& 
!!b&&"object"===typeof b&&b.hasOwnProperty("iat")}function Fc(a){a=Dc(a).Ge;retu 
rn"object"===typeof a&&!0===y(a,"admin")};function Gc(a,b,c){this.type=Hc;this.s 
ource=a;this.path=b;this.children=c}Gc.prototype.Jc=function(a){if(this.path.e() 
)return a=this.children.sub 

RangeError: Maximum call stack size exceeded 
    at RegExp.exec (native) 
    at RegExp.test (native) 
    at tc (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:63:86) 
    at ub (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:60:136) 
    at vb (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:43:1228) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:44) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 
    at Xb.h.remove (<MY_PROJECT_PATH>\node_modules\firebase-admin\lib\database\database.js:52:136) 

<MY_PROJECT_PATH>> 

<MY_PROJECT_PATH>> 

<MY_PROJECT_PATH>> 

回答

1

即使你是不是处理它,对remove()的调用仍然是基于异步/承诺的,并生成一个上下文来运行。Promise上下文相当大,并且您在这里用完堆栈并不意外。如果您真的需要这样的模式才能正常工作,可以批量更新 - 让child_added将值插入到“待删除”数组中,然后将该批次的条目作为单独任务一次处理,直到它成为空。在BlueBird(http://bluebirdjs.com/)库中有很多辅助方法可用于处理数组和Promises(可帮助完成此操作(例如,map/mapSeries))。

这不是一个真正的Firebase问题 - 每个其他VM(PHP,Java等)都有堆栈大小限制。最喜欢的人,V8的是可调的,如果你需要,你可以使用如下命令它查询(及调整):

node --v8-options | grep -B0 -A1 stack_size 

但我相信你最好的办法是构建程序,以尽量减少你的堆栈使用对于这种删除模式。增加堆栈大小总是会让你打开“现在是否足够大?”题。

0

Minmize分配给堆栈的内存。例如函数内部的静态数组,而不是使用动态数组。