3

I have a couple of JavaScript remoting functions used to count records and to display that count to the end user. The JavaScript remoting functions are on a Visualforce page, and the Visualforce page is embedded on a page layout of a custom object.

What is happening is that the javascipt remoting functions are supposed to count the number of records available after filters are set. However intermittently the user will receive the error “Unable to connect to server”.

I have a couple of JavaScript remoting functions are working against a custom object, and there are other remoting functions working on the Task object. These functions are doing nothing more than counting records in the system. The JavaScript remoting function counting records on the Task object are working more constistently than the JavaScript remoting functions counting records on the custom object.

I’m worried that this error may a result of the fact that the custom object is not indexed, and therefore counting records for that object may require more time than what is allowed for JavaScript remoting functions. If this is the case, should I do something to get the custom object indexed?

Also, I’m concerned that the “Unable to connect to server” error is a known bug, from what I have gathered on the forums. If this is the case is there a known fix?

Below is an example of the JavaScript remoting function on the Task object, to count the number of task records for the given parameters. This function is failing some of the time, mostly in the morning when first logging into the system.

//Javascript Remoting Function
controllerExampleCounter.asyncReviewedClosed(String("{!Example_Custom_Setting_Validation__c.OwnerId}"), function(result, event) {
    if (event.status) {
        $("#reviewedClosed").text(addCommas(result));
    } else if (event.type === "exception") {
        $("#reviewedClosed").text("Error: " + event.message);
    } else {
        $("#reviewedClosed").text("Error: " + event.message);
    }
}, {escape:true});

//Apex Function
@RemoteAction @ReadOnly
global static Integer asyncReviewedClosed(String owner_id)
{
    Integer incomplete = 0;

    try{
        incomplete = [Select count() 
            From Task 
            Where RecordType.Name = 'Qualification Task' 
                And CreatedById = :String.escapeSingleQuotes(owner_id) 
                And IsClosed = true 
                And CreatedDate = THIS_YEAR];
    } catch(Exception e) {
    }

    return incomplete;
}
5

The following is not officially support, so be careful, and is applied to all requests. Also, be aware that Salesforce.com's general HTTP request timeout may come into play.

<script>
_Visualforce.Ajax.timeout=120000;
...
</script>

And, BTW, Visualforce Remoting is a popular feature of Visualforce.

  • Increasing the timeout may indeed help if the user's author's Task object has a lot of records in it and the query is taking a long time to run. But would that cause the "Unable to connect to server" error? – zachelrath Sep 27 '12 at 17:47
  • @cwall, we will try this, but am just curious about where you got the info and what you know about it. Main reason I ask is that I see this param no where else on the web other than an Idea that you commented on and this post. Is this internal Salesforce knowledge or something you discovered and is working thus far? Just want to understand context. – hemmeter Apr 6 '13 at 14:26
3

It sounds like your Apex method is taking longer than the JavaScript Remoting timeout, which is 30 seconds.

To my knowledge JavaScript Remoting still doesn't allow you to specify a custom timeout. I researched this pretty heavily back in January or so and that was the answer I received.

I do have an idea on the IdeaExchange to allow user customizable timeouts. Please take a moment and vote that idea up: https://sites.secure.force.com/success/ideaView?id=08730000000gLukAAE

My suggestion for fixing your issue in the meantime would be to switch to executing this method as a web service call and use the AJAX toolkit to call the web service in your VisualForce page.

Here's some example code to add to a VisualForce page to call an Apex web service with the AJAX Toolkit. You'll need to define your method with the webService annotation and it will need to be in a global class.

<!-- Set the session ID for the AJAX toolkit to use automatically -->
<script type="text/javascript">
    var __sfdcSessionId = '{!GETSESSIONID()}';
</script>
<!-- Include the AJAX Toolkit -->
<script  src="/soap/ajax/25.0/connection.js" type="text/javascript"></script>
<script  src="/soap/ajax/25.0/apex.js" type="text/javascript"/></script>
<script  type="text/javascript">
    // Execute the Apex web service.
    sforce.apex.execute( '<namespace>/<class>',
        '<method name>',
        {ownerId: '<ownerId>'},
        {onSuccess: displayCount, onFailure: errorHandler, timeout: 300000 //timeout in ms}
        );

    function displayCount( result )
    {
        // Add your code here to update/display your count.
    }

    function errorHandler( error )
    {
        // Handle errors.
    }
</script>

Information on the webService annotation can be found here: http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_web_services_methods_considerations.htm#kanchor587

Here's a simpler method for querying the count directly via the AJAX Toolkit without relying on a webService method.

<apex:page >
<!-- Set the session ID for the AJAX toolkit to use automatically -->
<script type="text/javascript">
    var __sfdcSessionId = '{!GETSESSIONID()}';
</script>
<!-- Include the AJAX Toolkit -->
<script src="/soap/ajax/25.0/connection.js" type="text/javascript"></script>
<script src="/soap/ajax/25.0/apex.js" type="text/javascript"></script>
<!-- jQuery -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script type="text/javascript">
    $().ready( function() {
            queryCount();
        });

    function queryCount()
    {
        // Execute the Apex web service.
        sforce.connection.query(
            "SELECT Count() FROM Lead",
            {
                onSuccess: handleCount,
                onFailure: queryFailed, 
                timeout: 300000 // Set timeout to 5 minutes
            });
    }

    function handleCount( result )
    {
        // Add your code here to update/display your count.
        $( '#output' ).append( result.size );

    }

    function queryFailed( error )
    {
        // Handle errors.
        $( '#output' ).append( error );
    }
</script>
<div id="output">
</div>
</apex:page>

You might also consider creating a custom object to aggregate these totals on a nightly, hourly or semi-hourly basis by executing a scheduled Batch Apex job. You could then quickly query that table to display the requested data.

  • That idea has been sitting at an abysmal four votes for the past 7-8 months or so (including mine). I guess there just aren't enough people using JS Remoting in SFDC. – E.J. Wilburn Sep 7 '12 at 2:11
  • I promoted the idea. I can't imagine JS remoting will ever gain much traction if its unreliable. This morning i am going to try your approach of using a webservice and will post my findings. Thanks. – Tony H. Sep 7 '12 at 16:18
2

Antonio, is the call to the JS after the DOM is ready or just whenever it's loaded.

It's possible that the rest of the JS hasn't loaded when you attempt to invoke this function.

Also have you opened the debug log to see if the function is even being hit when the iFrame (the way VF loads pages inside of other page layouts) is being loaded.

Also, not sure about the JS, I think it's correct but it's possible that you should simplify the JS invoking the remote action (I'm using: $.ready() in jQuery):

$(function(){
    controllerExampleCounter.asyncReviewedClosed('{!Example_Custom_Setting_Validation__c.OwnerId}',function(){ ... });
});
}
  • Hi Jordan, the Javascript remoting function is called as soon as the DOM of the iframe is done loading. The javascript remoting functions usually return the error the first couple of attempts in the morning, then, after warmed up, work just fine. Salesforce premier support has been unable to help me with this issue, so i've come to you guys :) – Tony H. Sep 6 '12 at 16:45
  • That's weird, I mean the @RemoteAction function should work normally inside of the iFrame whenever it loads. Have you tried the same action just opening the VF page (full window, not inside of iFrame) to see if it loads)? – jordan.baucke Sep 6 '12 at 17:18
  • I just confirmed that it does timeout when just the visualforce page is opened as well.Error message: "Unable to connect to server". After refreshing the page 3 times i finally got a count of records on the Task object. This may not have as much to do with JSRemoting as it does with the aggregate query? Just trying to think this through.. – Tony H. Sep 6 '12 at 18:45
  • Try reworking the query and test if you have the same result: List<sObject> tasks = [SELECT Id...]; and than integer count...for(sObject task : tasks){ count++;} and see if it still has problems. – jordan.baucke Sep 6 '12 at 19:29
  • I would imagine that would take twice as long if you're iterating through the collection twice. Time is important as javascript remoting functions have a small window in which to get a result from the controller. – Tony H. Sep 6 '12 at 19:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.