Parse function time out management - javascript

In Parse Cloud Code there is a response time limit of 15s. We've been experiencing problems on certain requests that depend on external service requests.
If we have 4 promises, promise 1 & 2 create objects but if the request "runs out of time" on promise 3 we need to destroy whatever was created on the process. I'm cascading the error handling in a similar way as the following example:
var obj1, obj2, obj3;
query.find().then(function() {
obj1 = new Parse.Object('Anything');
return obj1.save();
}).then(function() {
obj2 = new Parse.Object('Anything');
return obj2.save();
}).then(function _success() {
obj3 = new Parse.Object('Anything');
return obj3.save();
}).then(function _success() {
response.success();
}, function _error(err) {
var errorPromises = [];
if (obj1 != undefined) errorPromises.push(deleteExternalStuff(obj1.id));
if (obj2 != undefined) errorPromises.push(deleteExternalStuff(obj2.id));
if (obj3 != undefined) errorPromises.push(deleteExternalStuff(obj3.id));
Parse.Promise.when(errorPromises).then(function _success() {
response.error();
}, function _error() {
response.error(err);
});
});
The deleteExternalStuff function makes a get request on one of the object's id and then returns an object.destroy() promise.
My problem is that the get query works but the destroy promises inside the deleteExternalStuff are not deleting the objects from the database. Any suggestions on how to handle this case?
EDIT:
I've tested and whenever a timeout occurs, the error IS INDEED executed but the destroy() is what is not working just right.
EDIT 2: Added a similar structure for the deleteExternalStuff function
function deleteExternalStuff(objectId) {
var query = Parse.Query('Another Object');
query.equalTo('objXXX', objectId);
return query.find().then(function _success(anotherBunchOfObjects) {
var deletePromises = _.map(anotherBunchOfObjects, function(obj) {
return obj.destroy();
});
return Parse.Promise.when(deletePromises);
}, function _error(error) {
console.log(error); // **ERROR LOG**
return Parse.Promise.as();
});
}
EDIT 3:
With further testing I added an error handler in deleteExternalStuff function and printed to log... Apparently the **ERROR LOG** prints the following: {"code":124,"message":"Request timed out"}
This makes me think that Parse doesn't permit the use of chained promises in error handling if you have already reached the timeout limit... :\
Suggestions for alternate solutions are appreciated.

To make sure all objects are deleted before your request is finished, you will have to wait until all promises are resolved:
var promises = [];
if (obj1 != undefined) promises.push(deleteExternalStuff(obj1.id));
if (obj2 != undefined) promises.push(deleteExternalStuff(obj2.id));
if (obj3 != undefined) promises.push(deleteExternalStuff(obj3.id));
Promise.all(promises).then(function() {
response.error(err);
});

Related

In calling URLs iteratively using http.get() and resolving using $q.all()

I am implementing this scenario where I have to fetch data from multiple URLs iteratively and process it with some business logic and display on screen. I am implementing this in the controller as it is a requirement. All is well until part-1 and I am getting the 6 promise objects in the promises array. But, I am not getting the data into metricData. I am seeing a null in the console while running in the browser. I am sure that the data is coming in the URL response. I feel I am doing something silly in the $q.all method. Is this correct?
var calculateMutationsInDepth = function(){
//Part-1
var promises=[];
var metricData=[];
for(var depth=0 ; depth<6 ; depth++){
var resourceUrl = urlService(depth);
promises.push($http.get(resourceUrl)
.then(function(response){
return response.data;
},function(status){
return status;
}));
}
//Part-2 Resolving the promise array below
$q.all(promises).then(function(data){
for(var eachResult=0; eachResult < data.length; eachResult++){
if(null != data[eachResult]){
var eachDataObject = data[eachResult];
//For debugging console.log(eachDataObject);
for(var objCount=0; objCount < eachDataObject.length; objCount++){
if(eachDataObject[objCount].scope === "PRJ" || eachDataObject[objCount].scope === "FIL")
metricData.push(eachDataObject[objCount]);
}
}
}
});
if(metricData != null){
analyzeMutationData(metricData); //Calling a function with the aggregated data array where business logic is present
}
};
calculateMutationsInDepth(); //Calling the above function
Yes, something silly.
As written, analyzeMutationData(metricData) is called synchronously whereas metricData is populated asynchronously inside the $q.all(promises).then() callback.
Also, as written the error handler function(status){ return status; } is inappropriate. Either :
omit the error handler entirely and allow any single $http error to prevent further processing in Part 2, or
return null, allowing processing in Part 2, and the if(dataObject != null) test in part 2 to filter out any such error.
Here's the revised code with a few other tidies and a demonstration of what can be done if calculateMutationsInDepth() returns a promise.
var calculateMutationsInDepth = function() {
//Part-1
var depth, promises = [];
for(depth=0; depth<6; depth++) {
promises.push($http.get(urlService(depth))
.then(function(response) {
return response.data;
}, function(error) {
return null; // error recovery - `dataObject` below will be null
}));
}
//Part-2 Aggregate the promises, extract metric data and apply business logic
return $q.all(promises).then(function(data) { // note `return` here
var dataObject, i, j, metricData = [];
for(i=0; i<data.length; i++) {
dataObject = data[i];
if(dataObject != null) {
for(j=0; j<dataObject.length; j++) {
if(dataObject[j].scope === "PRJ" || dataObject[j].scope === "FIL") {
metricData.push(dataObject[j]);
}
}
}
}
// Analyse here, inside the .then()
if(metricData.length > 0) { // metricData is an array and will never be null, therefore test metricData.length.
return analyzeMutationData(metricData);
}
return null;
});
};
calculateMutationsInDepth().then(function(analysis) {
// all complete
// `analysis` is either null or whatever `analyzeMutationData(metricData)` returned.
}).catch(function(error) {
console.log(error);
});
Hope this helps you out! Let me know if it doesn't.

Error Handling with WinJS

I'm new to Windows Phone development.
Going through the documentation I got to 'Using Promises' and probably missing something.
Trying to implement the code in the tutorial:
How to handle errors with promises (HTML)
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
} else {
}
args.setPromise(WinJS.UI.processAll());
}
WinJS.Utilities.ready(function () {
var input = document.getElementById('inputUrl');
input.addEventListener('change', changeHandler);
}, false);
};
app.oncheckpoint = function (args) {
};
function changeHandler(e) {
var input = e.target;
var resultDiv = document.getElementById("result");
var div2 = document.getElementById("div2");
WinJS.xhr({url: e.target.value})
.then(function (result) {
if (result.status === 200) {
resultDiv.style.backgroundColor = "lightGreen";
resultDiv.innerText = "Success";
}
return result;
})
.then(function (result) {
if (result.status === 200) {
resultDiv.style.backgroundColor = "yellow";
}
},
function (e) {
resultDiv.style.backgroundColor = "red";
if (e.message != undefined) resultDiv.innerText = e.message;
else if (e.statusText != undefined) resultDiv.innerText = e.statusTExt;
else resultDiv.innerText = 'Error';
});
}
app.start();
})();
If I write a simple string and not URL format i'm getting an unhanded exception. Where I thought that all exceptions will be handled by then() second parameter.
Don't really understand the difference between the XHR code above or this alternative:
WinJS.xhr({ url: e.target.value }).then(
function completed(result) {
if (result.status === 200) {
resultDiv.style.backgroundColor = "lightGreen";
resultDiv.innerText = "Success";
}
},
function error(e) {
resultDiv.style.backgroundColor = "red";
if (e.message != undefined) resultDiv.innerText = e.message;
else if (e.statusText != undefined) resultDiv.innerText = e.statusTExt;
else resultDiv.innerText = 'Error';
}
)
At the end of the tutorial there is example for using WinJS.promise.onerror.
I don't understand where and how to implement it.
If someone can set an example i'll appreciate it.
I'm not entirely sure what you mean by #1, but let me answer what I can.
First of all, if you chain promises together with multiple .then().then() calls, you need to make sure that each return value in each completed function is itself a promise. In the case of WinJS.xhr, there is only one promise involved. For this reason, your second code example is the right one, because in the first you're returning a non-promise result and attempting to attach another .then to it, which doesn't work.
Second, for Windows apps the proper practice is to use .done() for the last promise in the chain. When you have a single promise method like WinJS.xhr, use just .done().
The reason for this is that .done makes sure that exceptions that occur earlier in the chain do not get swallowed and thus disappear. It makes sure that all errors anywhere in the chain get routed to the error handler at the end.
What I think is happening with #1 as you describe it, is that if you give WinJS.xhr a non-URL, it'll throw an exception which will put the promise returned by WinJS.xhr into an error status. Your first .then() call looks for an error handler, but not seeing one, and because you're using a second unneeded .then, and aren't using .done at all, that exception doesn't surface in the promise flow and instead gets picked up by the debugger.
The purpose of WinJS.Promise.onerror is to provide a single handler for all exceptions that occur in promises. This is not useful for handling specific error cases like you're doing; it is meant more for implementing a general-purpose logger or such.
PS, I wrote a lot about promises in Appendix A "Demystifying Promises" in my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition.

In parse object.save(); doesnt return anything why?

Here is my code, it loops through forEach and prints out '1' but never returns from object.save() & never prints out 2, 3 or anything else. I have tried a bunch of other ways but none seems to work.
Note: response.succes(or error) is not being called anywhere, the code is definitely waiting for object.save() to be completed.
var promise = new Parse.Promise();
var query = new Parse.Query("SomeClass");
query.find().then(function(results) {
var promises = [];
results.forEach(function(object) {
object.set("SomeColumnName", true);
console.log('1');
promises.push(object.save(null, {
success: function(result) {
alert('2');
return ;
},
error: function(result, error) {
alert('3');
return ;
}
}));
});
Parse.Promise.when(promises).then(function() {
console.log('inside resolve');
promise.resolve();
}, function() {
console.log('inside reject');
promise.reject();
});
});
return promise;
You're on the right track, but you should take advantage of the fact that most of the sdk functions create and return promises for you. With those, you can substantially simplify the code:
// very handy utility library that provides _.each among many other things
// www.underscorejs.org
var _ = require('underscore');
// answer a promise to modify all instances of SomeClass
function changeSomeClass() {
var query = new Parse.Query("SomeClass");
// if there are more than 100 rows, set query.limit up to 1k
return query.find().then(function(results) { // find returns a promise
_.each(results, function(result) {
result.set("SomeColumnName", true);
});
return Parse.Object.saveAll(results); // and saveAll returns a promise
});
}
Wrap it in a cloud function and call success/error like this:
Parse.Cloud.define("changeSomeClass", function(request, response) {
changeSomeClass().then(function(result) {
response.success(result);
}, function(error) {
response.error(error);
});
});
You can only have one Parse request happening at a time for each object. If multiple requests are sent, all but the first are ignored. You're probably trying to do this while other threads are making Parse requests for those objects. I know that if you save an object, it also saves it's child objects, so you could be hitting a problem with that. Make sure you do as much as you can in background threads with completion blocks, or use saveEventually / fetchEventually where possible.

Conditional promises in WinJS

I've got two pieces of code which may or may not run when my app starts. Both produce a messageDialog, so the second must wait on the first. I'm trying to use promises to do this but I'm having issues with the returned value. Can someone point me in the right direction?
WinJS.Promise.as()
.then(function () {
// readTempFile returns a promise, see code below
if (localSettings.values["lastContent"] != 0) {
return readTempFile();
}else{
// what am I supposed to return here? false?
}
})
.then(function () {
// check for release notes
if (localSettings.values["release"] == null) {
var updates = "Updates in this version";
var msg = new Windows.UI.Popups.MessageDialog(updates, "Updates");
msg.commands.append(new Windows.UI.Popups.UICommand("OK", null, 0));
msg.showAsync();
}
});
function readTempFile(){
return new WinJS.Promise(function (complete, error, progress) {
// is my try / catch block redundant here?
try {
tempFolder.getFileAsync("tempFile.txt")
.then(function (file) {
file.openReadAsync().done(function (stream) {
// do stuff with the file
});
var msg = new Windows.UI.Popups.MessageDialog("unsaved work", "Warning");
msg.commands.append(new Windows.UI.Popups.UICommand("OK", null, 0));
msg.showAsync();
complete();
}, function () {
// file not found
error();
});
}
catch (e) {
logError(e);
error();
}
});
}
If both conditions are true, I get an access denied error. As I understand it, readTempFile() returns a promise object which my first then() statement should accept. But I'm not returning anything if the first conditional is met. I don't think that matters in this case as it just falls through to the next then, but it's not good programming.
EDIT:
Amended the readTempFile function to show that it produces a MessageDialog.
Well, let's try an analogy:
function fetchIfNotCached(){
if(!cached){
doSomething();
}
// nothing here
}
This is exactly like your case, only asynchronous. Because it utilizes promises you hook on the return value so:
what am I supposed to return here? false?
Anything you want, I'd personally probably just omit it and refactor it to if(!cached) return doSomething() in the .then. Promises chain and compose and you do not need to create them from callback interfaces unless there is a really good reason to do so.
As for readTempFile you're doing a lot of excess work as it looks like getFileAsync already returns a promise. This is a variation of the deferred anti pattern and can be rewritten as:
function(readTempFile){
return tempFolder.getFileAsync("tempFile.txt").then(function (file) {
return file.openReadAsync();
}).then(function (stream) {
// do stuff with the file, note the return as we wait for it
});
}
Found the answer. Inside the readTempFile function, I needed to add a done() to the showAsync() of my messageDialog, and put the complete() call in there. Otherwise, complete() was returning the promise while the dialog was still up.
function readTempFile(){
return new WinJS.Promise(function (complete, error, progress) {
// is my try / catch block redundant here?
try {
tempFolder.getFileAsync("tempFile.txt")
.then(function (file) {
file.openReadAsync().done(function (stream) {
// do stuff with the file
});
var msg = new Windows.UI.Popups.MessageDialog("unsaved work", "Warning");
msg.commands.append(new Windows.UI.Popups.UICommand("OK", null, 0));
msg.showAsync().done(function(){
// must be inside done(), or it will return prematurely
complete();
});
}, function () {
// file not found
error();
// have to add a complete in here too, or the app will
// hang when there's no file
complete();
});
}
catch (e) {
logError(e);
error();
}
});
}
After a couple of experiments, I figured that out myself.
As to what needed to return in my empty else statement, it was another WinJS.Promise.as()
WinJS.Promise.as()
.then(function () {
// readTempFile returns a promise, see code below
if (localSettings.values["lastContent"] != 0) {
return readTempFile();
}else{
return WinJS.Promise.as()
}
})
.then(function () {
// check for release notes
if (localSettings.values["release"] == null) {
var updates = "Updates in this version";
var msg = new Windows.UI.Popups.MessageDialog(updates, "Updates");
msg.commands.append(new Windows.UI.Popups.UICommand("OK", null, 0));
msg.showAsync();
}
});
I found the answer in a Google Books preview of Beginning Windows Store Application Development – HTML and JavaScript Edition By Scott Isaacs, Kyle Burns in which they showed an otherwise empty else statement returning a WinJS.Promise.as()

Dojo using deferred functions to get data in ajax callback function

I have a function with a return however in the function there is an async request which holds the value that is suppose to be returned by the function. I understand with the nature of async request the function will complete and not return a value while waiting on the async function to complete.
I attempted to use dojo deferred functions to have my function PostInformation() to return a value within the ajax request callback. I am having some issues and i am not sure where my issue is. Under is my code:
Dojo Deferred Function
function PostInformation(){
var hasErrors = false;
var containers = [dijit.byId("container1"), dijit.byId("container2")];
var Employee = {
//data
};
var def = new dojo.Deferred();
def = dojo.xhrPost({
url: 'hello',
content: Employee,
load: function (data) {
formErrors = {
"errors": true,
"fName": "123",
"surname": "456",
"oNames": "789",
"bSurname": "784585"
};
//formErrors = (JSON.parse(data)).formErrors;
$.each(formErrors, function (key, value) {
if (key == 'errors') {
hasErrors = value;
//console.log('hasErrors set to '+value);
}
});
if (hasErrors == true) {
for (var i = 0; i < containers.length; i++) {
var processingContainer = containers[i];
dojo.forEach(processingContainer.getChildren(), function (wid) {
var widgetName = wid.attr('id');
$.each(formErrors, function (key, value) {
if (key == widgetName && value.length > 0) {
var myWidget = dijit.byId(widgetName);
//var wdgName = dijit.byId(widgetName).attr("id");
var myWidgetValue = value;
myWidget.validator = function () {
//console.log('Attribute Name is :' + wdgName + ' Error Value is : ' + myWidgetValue);
//console.log(wdgName + " : "+myWidgetValue);
this.set("invalidMessage", myWidgetValue);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
}
}
console.log(hasErrors);
def.resolve(hasErrors);
},
error: function(err){
console.log(err);
def.reject(err);
}
});
def.then(function(data){
console.log('In the then function');
//alert('In the def.then and the results is : ' + data);
if(data == true){
return false;
}else{return true;}
},function(err){
return false;
alert('In the def.error and there has been an error ' + err);
});
//return the value of hasErrors here
};
Devdar, you are making heavy wether out of something quite simple. In particular, you don't need to loop through an object to access one of its properties, and the variable hasErrors is not really necessary.
Your code should simplify to something like this :
function PostInformation() {
var $containers = $("#container1, #container2");
var Employee = {
//data
};
return dojo.xhrPost({
url: 'hello',
content: Employee
}).then(function(data) {
data = JSON.parse(data);
var formErrors = data.formErrors;
if(formErrors.errors) {
$containers.each(function(i, c) {
$(c).children().each(function(wid) {
var val = formErrors[wid.id],
myWidget;
if(val) {
myWidget = dijit.byId(wid.id);
myWidget.validator = function() {
this.set("invalidMessage", val);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
//Send an enhanced error object down the "error" route
throw $.extend(formErrors, {
'message': 'PostInformation(): validation failure'
});
}
//Send the data object down the "success" route
return data;
});
};
PostInformation().then(function(data) {
console.log('PostInformation(): everything went OK');
//access/process `data` here if necessary
//and/or just display a nice "success" message to the user
}, function(err) {
console.error(err.message);
});
Barring mistakes on my part, this code should do everything you want and more. As with your own code, it processes the server's JSON response and returns a Promise, but that's where the similarity stops.
In your code, you seek to return a Promise which is eventually resolved with a boolean to indicate whether or not errors were detected. Whilst this will (if correctly written) meet your immediate needs, it is not the best Promise logic.
In my code, the Promise is resolved only if validation succeeds and rejected if validation fails for whatever reason. Not only is this logically correct behaviour for a Promise (success goes down the success route, and errors go down the error route) but as a bonus should (see note below) also allow you to pass more information to whetever function(s) eventually handle errors. I choose to pass the whole formErrors object enhanced with an error message, thus providing a great deal of freedom in the error handler to display/log/etc as much or as little as is appropriate, and with virtually no assumption inside PostInformation() as to what will happen subsequently. You currently believe that you will only read and act on the boolean formErrors.errors but it could be beneficial to pass as much error data as possible thus allowing yourself the freedom to change your mind at a later date without needing to change anything in PostInformation().
In this regard you can think of PostInformation() as an agent of the server-side service; and like that service, it can be written with incomplete knowledge (or maybe no knowledge at all) of how the (promise of) data/errors it delivers will be used by "consumer code".
NOTE: I have to admit that I'm not 100% familiar with Dojo's Promises, so I'm not sure that a JS plain object can be thrown in the way I indicate. I have found evidence but not proof that it can. For that reason, I am cautious above in saying "your code should simplify to something like this" Anyway, that issue aside, the principle of sending success down the success route and errors down the error route should still apply.
I'd suggest this where you create your own Deferred() object, return it from your PostInformation() function and then register .then() handlers on it so you can pick up the resolve or reject on your own Deferred object that happens inside the PostInformation() function.
The way you had it you were creating your own Deferred() object, but then immediately overwriting it with the xhrPost return result which meant def is now something else and you weren't returning your Deferred from PostInformation() so it can be used outside that function to track the progress.
function PostInformation() {
var hasErrors = false;
var containers = [dijit.byId("container1"), dijit.byId("container2")];
var Employee = {
//data
};
var def = new dojo.Deferred();
dojo.xhrPost({
url: 'hello',
content: Employee,
load: function (data) {
formErrors = {
"errors": true,
"fName": "123",
"surname": "456",
"oNames": "789",
"bSurname": "784585"
};
//formErrors = (JSON.parse(data)).formErrors;
$.each(formErrors, function (key, value) {
if (key == 'errors') {
hasErrors = value;
//console.log('hasErrors set to '+value);
}
});
if (hasErrors == true) {
for (var i = 0; i < containers.length; i++) {
var processingContainer = containers[i];
dojo.forEach(processingContainer.getChildren(), function (wid) {
var widgetName = wid.attr('id');
$.each(formErrors, function (key, value) {
if (key == widgetName && value.length > 0) {
var myWidget = dijit.byId(widgetName);
//var wdgName = dijit.byId(widgetName).attr("id");
var myWidgetValue = value;
myWidget.validator = function () {
//console.log('Attribute Name is :' + wdgName + ' Error Value is : ' + myWidgetValue);
//console.log(wdgName + " : "+myWidgetValue);
this.set("invalidMessage", myWidgetValue);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
}
}
console.log(hasErrors);
def.resolve(hasErrors);
},
error: function (err) {
console.log(err);
def.reject(err);
}
});
return def.promise;
};
PostInformation().then(function (data) {
console.log('In the then function');
// process data value here which will contain the value you resolved with
}, function(err)
// process an error in the ajax result here
});
I think this is more of an issue with design of the function then.
Since the xHR call is asynchronous, the postInformation shouldn't really return anything unless it's the Deferred object itself. An alternative option is to have postInformation do some sort of event publishing (dojo/topic), that other functions will subscribe to and know how to handle said events.

Categories

Resources