-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Promise.serial() makes my imp04 device crash.
I found a workaround by reimplementing this function with a tiny variation, but the fact that it solves the issue makes no sense for me. I don't know what I am talking about, but I suspect a bug in the squirel VM itself. So please consider my test case.
I tried to simplify my app, so this sample may seem to be too complex for the features it implements.
RUN on imp04, device or agent.
#require "Promise.lib.nut:4.0.0"
// Here we will test several variations of Promise.serial
function Promise_serial(promises) {
// static method
return Promise.serial(promises);
}
function Promise_serial1(promises) {
// Copy/paste of Promise.serial
local i = 0;
return Promise.loop(
@() i < promises.len(),
function () {
return "function" == type(promises[i]) // you'll see that this i integer will become a string??
? promises[i++]()
: promises[i++];
}
)
}
function Promise_serial2(promises) {
// Just a tiny change in Promise.serial
local i = 0;
return Promise.loop(
@() i < promises.len(),
function () {
// I don't know why but I had to change the order here
local res = promises[i++];
if ("function" == type(res)) {
res = res();
}
return res;
}
)
}
// My simplified app
// I removed everything that is not required to reproduce the bug
/**
* Simulates an asynchronous command that is sent to a device throuh a serial interface
* and its response.
*/
function executeCommand(cmd) {
server.log("--> " + cmd);
return Promise(function(resolve, reject) {
imp.wakeup(0, function() {
server.log("<-- " + cmd);
resolve(true);
});
});
}
currentCommandPromise <- null;
/**
* Wrapper that make sure that only one command is running at a time.
*/
function commandWrapper(callback) {
if (null == currentCommandPromise) {
currentCommandPromise = callback();
}
else {
currentCommandPromise = currentCommandPromise.then(
function(value) { // onFulfilled
return callback();
},
function(reason) { // onError
logger.error("Failed callback: " + reason);
return callback();
}
);
}
return currentCommandPromise;
}
/**
* Callback executed when the device starts
*/
function onStartCallback() {
local promises = [
function() {
return executeCommand("onStartCallback");
},
// We would expect more commands here
];
return commandWrapper(function() {
return Promise.serial(promises);
});
}
// My tests with the Promise.serial variation
function test() {
server.log("Run test");
local promises = [
function() {
return onStartCallback();
},
// We would expect more commands here
];
Promise_serial(promises);
}
function test1() {
server.log("Run test1");
local promises = [
function() {
return onStartCallback();
},
// We would expect more commands here
];
Promise_serial1(promises);
}
function test2() {
server.log("Run test2");
local promises = [
function() {
return onStartCallback();
},
// We would expect more commands here
];
Promise_serial2(promises);
}
// main
// Pick the test you want
test(); // crash with ERROR: indexing array with string
//test1(); // crash with ERROR: indexing array with string
//test2(); // this test works fine
If you run test() or test1() which runs the same code:
2021-03-22T21:57:01.360 +00:00 | [Agent] | Run test
2021-03-22T21:57:01.374 +00:00 | [Agent] | ERROR: indexing array with string
2021-03-22T21:57:01.374 +00:00 | [Agent] | ERROR: in commandWrapper agent_code:64
2021-03-22T21:57:01.374 +00:00 | [Agent] | ERROR: from unknown electricimp#promise.lib.nut#4.0.0:251
2021-03-22T21:57:01.374 +00:00 | [Agent] | ERROR: from unknown electricimp#promise.lib.nut#4.0.0:219
But if you run test2() it is OK
2021-03-22T21:57:25.095 +00:00 | [Agent] | Run test2
2021-03-22T21:57:25.133 +00:00 | [Agent] | --> onStartCallback
2021-03-22T21:57:25.153 +00:00 | [Agent] | <-- onStartCallback
I let you play with this test2() and try to understand what makes the difference. From my understanding, it is the position of the i++. There is no reason for it, but in the crashing tests, this integer suddenly becomes a string!?!
I've spend quite a lot of time to investigate, don't hesitate to point out any stupid error I made, but please enlighten me ;-)