ArtOfWarfare
ArtOfWarfare

Reputation: 21476

Parse Cloud Code Ending Prematurely?

I'm writing a job that I want to run every hour in the background on Parse. My database has two tables. The first contains a list of Questions, while the second lists all of the user\question agreement pairs (QuestionAgreements). Originally my plan was just to have the client count the QuestionAgreements itself, but I'm finding that this results in a lot of requests that really could be done away with, so I want this background job to run the count, and then update a field directly on Question with it.

Here's my attempt:

Parse.Cloud.job("updateQuestionAgreementCounts", function(request, status) {
    Parse.Cloud.useMasterKey();
    var query = new Parse.Query("Question");
    query.each(function(question) {
        var agreementQuery = new Parse.Query("QuestionAgreement");
        agreementQuery.equalTo("question", question);
        agreementQuery.count({
            success: function(count) {
                question.set("agreementCount", count);
                question.save(null, null);
            }
        });
    }).then(function() {
        status.success("Finished updating Question Agreement Counts.");
    }, function(error) {
        status.error("Failed to update Question Agreement Counts.")
    });
});

The problem is, this only seems to be running on a few of the Questions, and then it stops, appearing in the Job Status section of the Parse Dashboard as "succeeded". I suspect the problem is that it's returning prematurely. Here are my questions:

1 - How can I keep this from returning prematurely? (Assuming this is, in fact, my problem.)

2 - What is the best way of debugging cloud code? Since this isn't client side, I don't have any way to set breakpoints or anything, do I?

Upvotes: 0

Views: 241

Answers (2)

ArtOfWarfare
ArtOfWarfare

Reputation: 21476

I was able to utilize promises, as suggested by knshn, to make it so that my code would complete before running success.

Parse.Cloud.job("updateQuestionAgreementCounts", function(request, status) {
    Parse.Cloud.useMasterKey();
    var promises = [];  // Set up a list that will hold the promises being waited on.
    var query = new Parse.Query("Question");
    query.each(function(question) {
        var agreementQuery = new Parse.Query("QuestionAgreement");
        agreementQuery.equalTo("question", question);
        agreementQuery.equalTo("agreement", 1);

        // Make sure that the count finishes running first!
        promises.push(agreementQuery.count().then(function(count) {
            question.set("agreementCount", count);

            // Make sure that the object is actually saved first!
            promises.push(question.save(null, null));
        }));
    }).then(function() {
        // Before exiting, make sure all the promises have been fulfilled!
        Parse.Promise.when(promises).then(function() {
            status.success("Finished updating Question Agreement Counts.");
        });
    });
});

Upvotes: 0

knshn
knshn

Reputation: 3461

status.success is called before the asynchronous success calls of count are finished. To prevent this, you can use promises here. Check the docs for Parse.Query.each.

Iterates over each result of a query, calling a callback for each one. If the callback returns a promise, the iteration will not continue until that promise has been fulfilled.

So, you can chain the count promise:

agreementQuery.count().then(function () {
    question.set("agreementCount", count);
    question.save(null, null);
});

You can also use parallel promises to make it more efficient.

There are no breakpoints in cloud code, that makes Parse really hard to use. Only way is logging your variables with console.log

Upvotes: 1

Related Questions