This discussion is archived
12 Replies Latest reply: Oct 9, 2013 8:26 AM by tdsacilowski RSS

Error Popup When using AJAX or Dynamic Action Refresh for Region or Report

tdsacilowski Newbie
Currently Being Moderated

Hello,

 

I've been having an issue with an application I developed and I've been banging my head against the wall with this for some time without any success. Several pages in my application rely on using AJAX to refresh a region on the page with updated data, running every 5 seconds. I have the following code in my Region Footer:

 

var refresh_region = function (region_in) {
    try {
        jQuery(region_in).trigger('apexrefresh');
    } catch (e) {
        //Suppress error messages
    } finally {
        setTimeout(function() {refresh_region(region_in)}, 5000);
    }
}
refresh_region('##REGION_STATIC_ID#');

 

What happens is that I often get an popup window with the title "Message from webpage:" and one of the following error descriptions (with the latter being the most common):

  •     Error: error - HTTP Version Not Supported
  •     Error: error - Unknown

 

The problem is that this page is used on keyboard-less kiosks, and once the error popup displays, the page stops responding and user interaction is required to click the "Ok" button. Another issue, which is even more frustrating, is that these windows will pile up on top of each other almost a hundred deep at times, to the point where sometimes I need to force quit the browser or reboot the kiosk. There are also instances where the entire application becomes unresponsive and none of the pages will load. The only way to resolve this is to have my DBA restart Glassfish. He's gone through some of the logs but he's not seeing anything specific that's helping him understand why this keeps happening but he feels that all these popups are eating up connections until the server runs out.

 

This has been a recurring issue since the application went live and I had hoped that using a try{} catch{} block would prevent these errors popups but no luck. I also made a copy of the page today and moved the refresh functionality into a Dynamic Action using the Timer plugin but the popup still appears. I'm monitoring to see if it happens as often as with the AJAX approach.

 

Ultimately, there are two issues here:

  1. What's causing the error in the first place?
  2. How can I prevent the error popup windows until I can figure out #1

 

I've tried anything I can find online for disabling the popups, all without any luck:

  • Using try{} catch{}
  • Disabling script debugging in IE
  • Unchecking  "Display a notification about every script error"
  • Intercepting the window.onerror event

 

Does anyone have any suggestions on how I can prevent these popups?

 

I have a copy of the application on apex.oracle.com:

  • Workspace: SCCC_TEST
  • User/Pass: TEST/test
  • Page: 5

 

Thanks!

  • 1. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    NoGot Explorer
    Currently Being Moderated

    Hello!

     

    Two year ago i also developed applications for kiosks on APEX 3.1, so a can understand you :-)

    I think that your problem is:

    you are calling

    jQuery(region_in).trigger('apexrefresh'); 

    but this call triggers event, and runs without waiting regions refresh. So, if your regoin refresh takes more than 5 sec. second call will start without ending previous call. This function run asynchronous.


    On my kiosks i've used direct call of region refresh function named $a_report. And i changed this function so it returns the Jquery promise object, and i can write like this:


    $a_report(region_id,1,15,15,null,null,args,!$this.cached)

      .done(function(){

      // something on success

      })

      .fail(function(){

      // raising error or rebooting kiosk

      });


    But it was at APEX 3.1.

    In APEX 4.2 you can use apex.server.process with correct parameters, this function returns jqXHR object that can be used as in my code above. What parameters, i think you may find in APEX javascript libraries.

    Read about this JavaScript APIs

  • 2. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    tdsacilowski Newbie
    Currently Being Moderated

    Thanks for the reply!

     

    I've used apex.server.process before but only with on-demand processes. However, the region I'm trying to refresh is a report region, so I'm not sure how I can use apex.server.process to refresh the report unless I change the region to HTML and write a procedure that outputs the report HTML directly. In other words, not using the APEX report functionality.

  • 3. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    NoGot Explorer
    Currently Being Moderated

    No, no, no!

     

    I mean, that you can explore APEX javascript libraries, find how APEX refreshes report region, and use such code. I think there is a call to the Jquery.ajax function. Find what parameters it takes when refreshes region.

  • 4. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    NoGot Explorer
    Currently Being Moderated

    I found it in the widget.report.js file.

    When apexrefresh event triggers, it calls

    function _refresh ( pId, pData ).

    it takes pId - region internal id.

    In code of _refresh we can see that it sets

    lData.x01 = pId

    and then calls

    server.widget ("classic_report", lData, lOptions); - this refreshes your report!

    So, server.widget returs The jqXHR Object that can be usefull. Because it provides promise interface, and we can call it like this:

    server.widget ("classic_report", lData, lOptions).done(function(){ setTimeout(another_refresh, 5000) });

     

    Try this. I think it can help you.

  • 5. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    tdsacilowski Newbie
    Currently Being Moderated

    Sorry for the late response to this... a few other priorities took my attention away, but I'm back to trying to address this issue. So looking at the code for widget.report.js, I see the following _refresh function:

     

    function _refresh(pId, pData) {
            var lData = pData || {},
                lOptions = {};
            // register callback for success
            function _success(pResponse) {
                // This looks a little bit complicated and it is! To avoid screen flicker
                // when the HTML code is inserted into the DOM and JavaScript code modifies the
                // code afterwards (which takes some time), we are injecting the HTML code in
                // a temporary hidden area and do all our modifications and after that we
                // are replacing the existing report_xxx_catch with the new version.
                var lTemp = $u_js_temp_drop();
                $("#report_" + pId + "_catch", apex.gPageContext$)
                    .attr("id", "report_" + pId + "_catch_old");
                $(lTemp)
                    .html(pResponse);
                $("#report_" + pId + "_catch_old", apex.gPageContext$)
                    .replaceWith($("#report_" + pId + "_catch", apex.gPageContext$));
                $(lTemp)
                    .empty();
                // Trigger the after refresh event, and pass the current report Id convenience.
                // Event is triggered on table element with the ID equal to "report_" + pID + "_catch".
                // This element is not exposed in any templates and output by our engine, so is safe to
                // use.
                // Event handlers can be bound to this element in conjunction with the jQuery "live"
                // bind type, or can be bound to higher element (such as the main region ID) and use
                // the regular bind type. The latter works because the event bubbles and is how this
                // is handled within the dynamic action framework.
                //
                $("#report_" + pId + "_catch", apex.gPageContext$)
                    .trigger("apexafterrefresh", pId);
            }
            // Pass region ID via x01 parameter
            lData.x01 = pId;
            // Set the components page items to submit, if they are defined
            if (report.gPageItemsToSubmit[pId] !== undefined) {
                lData.pageItems = report.gPageItemsToSubmit[pId];
            }
            // Register success callback
            lOptions.success = _success;
            // TODO Add support for an appropriate loading indicator
            // Set HTML data type, that's what we want here
            lOptions.dataType = "html";
            // Make the call
            server.widget("classic_report", lData, lOptions);
            // Trigger the before refresh event, and pass the current report Id convenience.
            // Event is triggered on table element with the ID equal to "report_" + pID + "_catch".
            // This element is not exposed in any templates and output by our engine, so is safe to
            // use.
            // Event handlers can be bound to this element in conjunction with the jQuery "live"
            // bind type, or can be bound to higher element (such as the main region ID) and use
            // the regular bind type. The latter works because the event bubbles and is how this
            // is handled within the dynamic action framework.
            $("#report_" + pId + "_catch", apex.gPageContext$)
                .trigger("apexbeforerefresh", pId);
        }

     

    I can see where the function is calling server.widget. I'm thinking that my issue is being cause by server.widget encountering an error communicating with the server and since there's nothing handling the exception (as best as I can tell, at least), its generating that error pop-up. I know I need to find out what's causing the error in the first place but as a work-around I'd like to catch the exception and attach an empty function in order to prevent the pop-up. How would I do this?

     

    I did the following on one of my pages that's using an OnDemand process (rather than a Dynamic Action refresh):

     

    apex.server.process(
        'F_NEXT_STUDENT',
        { x01:  '&P7_WORKSTATION_IN.'},
        { type: 'GET',
          dataType: 'text',
          async: false,
          timeout: 2000,
          success: function(pData) { apex.jQuery('#next_student_div').html(pData); },
          error: function(x,t,m) { }
    });

     

    But I'm not sure how I would do this in the context of a Dynamic Action region refresh?

     

    Thanks for any advice on this!

  • 6. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    Tom Petrus Expert
    Currently Being Moderated

    actually, an $.ajax call is made here, so you could probably hook into the jquery global ajax event handlers. Global Ajax Event Handlers | jQuery API Documentation

    Especially .ajaxError() | jQuery API Documentation is of note.

  • 7. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    tdsacilowski Newbie
    Currently Being Moderated

    I had thought about that previously and added the following to the page "Functions and Global Variable Declaration":

     

    $( document ).ajaxError(function() { });

     

    But this didn't seem to work to catch the exception(s).

  • 8. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    tdsacilowski Newbie
    Currently Being Moderated

    After some more digging, I found this in server.js (which defines the apex.server namespace) which seems to be the error handler in the server.widget call:

     

    function _error( pjqXHR, pTextStatus, pErrorThrown, pOptions ) {
        var lMsg,
            lResult = false;
        _removeLoadingIndicator( pOptions.loadingIndicator );
        // TODO Handle APEX standard errors here $$$ (eg. session expired, ...)
        // call error callback if one is specified
        if ( $.isFunction( pOptions.callback ) ) {
            lResult = pOptions.callback( pjqXHR, pTextStatus, pErrorThrown );
        } else if ( pjqXHR.status !== 0 ) {
            // When pjqXHR.status is zero it indicates that the page is unloading
            // (or a few other cases that can't be distinguished such as server not responding)
            // and it is very important to not call alert (or any other action that could
            // potentially block on user input or distract the user) when the page is unloading.
            if ( pTextStatus === "APEX" ) {
                // If this is an APEX error, then just show the error thrown
                lMsg = pErrorThrown;
            } else {
                // Otherwise, also show more information about the status
                lMsg = "Error: " + pTextStatus + " - " + pErrorThrown;
            }
            window.alert( lMsg );
        }
        return lResult;
    } // _error
    

     

    Line 21 is apparently where the error alert is being thrown. Is it possible to override this function locally and comment that part out?

     

    Thanks!

  • 9. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    Tom Petrus Expert
    Currently Being Moderated

    Once I started thinking about the ajax handler I started wondering if the ajax would actually throw an error at all, and if it isn't simply the success firing anyway but throwing some error because it can not handle the return (an error page html for example). Not sure.

    You can try to use this code which will override the existing call and will allow to call _call with your own parameters. _call is a private member so it is not accessible so this is probably the best alternative. Not really a hack in my book. The structure is in place so why not.

    //preserve original function
    var asw_orig = apex.server.widget;
    //override existing function
    apex.server.widget = function(pName, pData, pOptions){
      var lOpts = pOptions;
      //set the error handler function
      lOpts.error = function(){alert("this is my error handler function");};
      //pass along the variables to the original call
      asw_orig(pName, pData, lOpts);
    };

    I was wondering if maybe the session may have expired at one point and therefor you are getting these errors, since the refresh is not aware of that and is thus making invalid calls. Just throwing something out there.

  • 10. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    tdsacilowski Newbie
    Currently Being Moderated

    Brilliant! This worked like a charm (at least so far as I can tell). I made some small modifications just for my own purposes ("type" and "async" are the same values as in the original _call function but I wanted to add it here as a reminder that I can use this method to change it or pass other jQuery.ajax properties:

     

    //preserve original function  
    var asw_orig = apex.server.widget;
    //override existing function
    apex.server.widget = function(pName, pData, pOptions) {
        
        var lOptions = $.extend( pOptions,
            { type: "post",
              async: true,
              timeout: 5000 ,
              error: function(pjqXHR, pTextStatus, pErrorThrown) { /*alert(pTextStatus);*/ }
            });
        
        //pass along the variables to the original call
        asw_orig(pName, pData, lOptions);
    };

     

    Also, I think you have a valid point in suggesting that maybe the sessions are expiring. For example, the page that I'm specifically referring to in this thread is a page sign-in page, displayed on a kiosk that only displays the current amount of people waiting for each area (this is the 5 second ajax refresh) and allowing a customer to swipe an ID card and enter a specific queue. The only time the browser is closed is if there's an error so the sessions should be timing out eventually (there's no authentication on the page, so I'm assuming this is the browser session).

     

    What happens in this case? I'm assuming that the ajax request will fire and since I have an empty function as the error handler it will keep trying to perform the request every 5 seconds but never complete unless the browser is restarted. Is there a way that I can check to see if the session is in fact still active? Should I instead reload the page in my error callback? I apologize in advance if I seem a bit fuzzy with regard to sessions. I'm still trying to fully understand the differences between browser session, session ID in the cookie, and session state.

     

    Thanks!

  • 11. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    Tom Petrus Expert
    Currently Being Moderated

    It's specifically the apex session I'm talking about. Even with no authentication there will be an apex session for that anonymous user and it can expire just as well and has the same timeout as other sessions (steered from workspace (or instance? Can't remember) and application settings). The ajax calls generated will use the session identifier that the current page has, and will be used by either referencing &APP_SESSION. (so, during rendering) or getting the identifier with $v("pInstance"). This means though that once the session has expired the page will still make calls with that now invalid session identifier. That is my guess. You could indeed just reload the page when you get an ajax error, and as the page is public that should fetch a new session. Worth a try I suppose - otherwise you'll just get a string of ajax errors and the data on your report will grow stale.

    (in the same vein, there is also a session timeout plugin created by skillbuilders, could be worth a look but haven't done so myself yet: Free Oracle APEX Plug-Ins | SkillBuilders)

  • 12. Re: Error Popup When using AJAX or Dynamic Action Refresh for Region or Report
    tdsacilowski Newbie
    Currently Being Moderated

    So I'm still having issues with this application. The answer above was correct in that it prevented the error popups from being displayed, which was certainly a big step in the right direction. However, I'm still having issues with the Glassfish server crashing quite often. The log shows the following two error messages:

    [#|2013-10-09T04:12:08.528-0400|WARNING|oracle-glassfish3.1.2|com.sun.grizzly.config.GrizzlyServiceListener|_ThreadID=11;_ThreadName=Thread-2;|GRIZZLY0023: Interrupting idle Thread: http-thread-pool-80(168).|#]

     

    [#|2013-10-09T04:12:08.528-0400|SEVERE|oracle-glassfish3.1.2|grizzly|_ThreadID=11;_ThreadName=Thread-2;|doSelect exception

    1. java.util.concurrent.RejectedExecutionException: The thread pool's task queue is full, limit: 4096

                    at com.sun.grizzly.util.AbstractThreadPool.onTaskQueueOverflow(AbstractThreadPool.java:473)

                    at com.sun.grizzly.util.SyncThreadPool.execute(SyncThreadPool.java:191)

                    at com.sun.grizzly.util.GrizzlyExecutorService.execute(GrizzlyExecutorService.java:162)

                    at com.sun.grizzly.http.StatsThreadPool.execute(StatsThreadPool.java:127)

                    at com.sun.grizzly.NIOContext.execute(NIOContext.java:510)

                    at com.sun.grizzly.NIOContext.execute(NIOContext.java:488)

                    at com.sun.grizzly.SelectorHandlerRunner.handleSelectedKey(SelectorHandlerRunner.java:370)

                    at com.sun.grizzly.SelectorHandlerRunner.handleSelectedKeys(SelectorHandlerRunner.java:263)

                    at com.sun.grizzly.SelectorHandlerRunner.doSelect(SelectorHandlerRunner.java:200)

                    at com.sun.grizzly.SelectorHandlerRunner.run(SelectorHandlerRunner.java:132)

                    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

                    at java.lang.Thread.run(Thread.java:662)

    |#]

    The first one ("interrupting idle Thread...") is showing up thousands of times in the logs. It seems that TomPetrus was right in that the session is expiring within APEX but my AJAX event is still firing with the expired pInstance value. My guess is that my AJAX calls (which fire every 5 seconds to poll the DB on about 20 or so machines) are timing out and eating up Glassfish threads. What I've done for now (just to see if it helps at all) is to set my max session time for the application to be 0 (indefinite). I don't quite know how the session cleanup job deals with such sessions but I figured it was worth a try until I find a better solution.

     

    As for the plugin mentioned above, I looked at the source for it and it seems that the "ping" feature they use is based on the same type of AJAX call from apex that I am using; in other words, it will try to use the same pInstance value as my AJAX calls:

     

       _pingSession: function(){
          var uiw = this;
          var queryString;
          apex.debug('Session Timeout: _pingSession (start)');
          queryString = {
             p_flow_id: $('#pFlowId').val(),
             p_flow_step_id: $('#pFlowStepId').val(),
             p_instance: $('#pInstance').val(),
             p_request: 'PLUGIN=' + uiw.options.ajaxIdentifier
          }
          
          $.ajax({
             type: 'POST',
             url: 'wwv_flow.show',
             data: queryString,
             dateType: 'text',
             async: true,
             success: function(data){
                apex.debug('Ajax request successful');
                clearTimeout(uiw._values.pingID);
                uiw._startPingTimer();
                uiw._stopTimers();
                uiw._startTimers();
             }
          });

     

    Any suggestions on how I can possibly handle this?

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points