I came across a ticket recently in which a customer was encountering an error in their nodejs logic when run within Apigee Edge. Curiously, the problem happened only when the nodejs logic ran in the Edge container, and did not occur when the code ran outside of Apigee Edge, for example on the regular node v8 engine.
The nodejs logic was throwing an exception, which caused the API proxy itself to return with this error:
{"fault":{"faultstring":"Script exited","detail":{"errorcode":"scripts.node.ScriptExited"}}}
Upon examination of the server log files, it seemed that the nodejs code was throwing an exception:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:777) ~[na:1.8.0_101]
at java.util.TimSort.mergeAt(TimSort.java:514) ~[na:1.8.0_101]
at java.util.TimSort.mergeForceCollapse(TimSort.java:457) ~[na:1.8.0_101]
at java.util.TimSort.sort(TimSort.java:254) ~[na:1.8.0_101]
at java.util.Arrays.sort(Arrays.java:1438) ~[na:1.8.0_101]
Kinda bizarre!
By the way, as an developer building API Proxies on Edge you would not see this exception unless you were using the OPDK, and you examined the Message Processor system.log. But you would see the ScriptExited problem, and you might notice that your nodejs app had been restarted.
There is a simple solution. The code in question was calling a sort on a Javascript array.
In JDK6 (and maybe 7?) this error didn’t occur. But Apigee Edge now runs on Java 8, and the error popped up. The sort function that was causing the exception looked something like this:
arr.sort(function(a, b) {
return parseFloat(a) > parseFloat(b) ? -1 : 1;
});
Looks benign enough, right?
But when JS runs in Apigee Edge, it runs within a Java container (Rhino, actually). And Java says that the comparison function must comply with the Comparable contract, one part of which says that for equal values, the function must return zero.
To avoid the exception and avoid the ScriptExited error, the above code can be replaced with:
arr.sort(function(a, b) {
var f1 = parseFloat(a), f2 = parseFloat(b);
return f1 == f2 ? 0 : f1 > f2 ? -1 : 1;
});