[resolved] beforeRender: multiple async requests: ECONNRESET



  • Hi,

    jsReport: 1.10.0

    I've hit a curious problem but I think the problem is the lack of understanding of how the done() callback works.

    I have a requirement for a report that requires to gather the data from multiple rest endpoints (multiple async requests).

    1. first I obtain the token from the token service.
    2. then I pass the token and the "done" function to the function that gets the data from other service
      That works ok.

    But if I, in the step 2, add another request simultaneously, I'm unable to combine the results as I hit the ECONNRESET.
    This other request, if I omit the request in step 2, proceeds fine so both requests are fully valid and authenticated requests.

    Any ideas on how can I combine the multiple request and call done() as soon as it's done?

    In the sample below I've deleted some parts so might have some issues, but basically I would like to wait for once the both requests are finished, I'd liket to do some checks and then call done.

    var request = require('request');
    var https = require('https');
    var http = require('http');
    
    var proxiedRequest = request;
    
    var data = {
        areas: null,
        fms: null
    };
    
    function beforeRender(req, res, done)  {
        
        console.log('-------------------- INIT ------------------------');
        req.data = req.data || {};
    
        try {
             getToken(req, done);
        }
        catch (err) {
            console.log('----- ERROR ----');
            done(err)
        }
    }
    
    function getToken(req, done) {
        var options = {
            method: 'POST',
            url: '.../getToken',
            headers: {
                'content-type': 'application/x-www-form-urlencoded',
                'Cache-Control' : 'no-cache'
            },
            form: {
                ...
            },
            timeout: 10000
        };
        console.log('sending the request');
    
        proxiedRequest(options, function(error, response, body) {
            console.log(body.token);
            getAGSData(JSON.parse(body).token, req, done);
        }, function (err) {
            console.log('Error while getting the token: ', err);
        });
    
    }
    
    function getAGSData(token, req, done) {
        console.log('--------------------------- AGOL Data Retreival ------------------------');
        if (!token) {
            done({
                error: 'No token provided.'
            });
            // Not necessary I reckon. I don't know. write it the first time.
            return;
        }
    
        try {
            var query = '1=1 AND TYPE=\'RAMP\'';
            
            console.log('Querying the data with the query: ', query);
            
            // Make the request
            proxiedRequest({
                    method: 'GET',
                    url: '.../FeatureServer/0/query',
                    qs: {
                        f: 'json',
                        where: query,
                        outfields: '*',
                        returnGeometry: false,
                        token: token,
                        orderByFields: 'LABEL'
                    },
                    headers: {
                        'Cache-Control' : 'no-cache'
                    }
                },
                (error, response, body) => {
                    console.log('------------- AGOL Response -----------');
                    if (error) {
                        console.error(error);
                        done('Error');
                    }
                    var features = JSON.parse(body).features || [];
                    req.data.mydata = features;
                    data.areas = features;
                    console.log(JSON.stringify(data));
                    done();
                }
            );
            
            /*proxiedRequest(
                {
                    method: 'GET',
                    url: '.../other/FeatureServer/0/query',
                    rejectUnauthorized: false,
                    qs: {
                        f: 'json',
                        where: '1=1',
                        outfields: '*',
                        returnGeometry: false
                    }
                },
                (error, response, body) => {
                    console.log('------------- BMAGISWEB Response FMS: -----------');
                  if (error) {
                    console.error(error);
                    console.log(response);
                    console.log(body);
                    done('Error');
                    return;
                  }
                  
                  var features = JSON.parse(body).features;
                  req.data.mydata = features;
                  // console.log(error);
                  // console.log(response);
                  console.log(JSON.parse(body).features);
                  data.fms = features;
                  console.log(JSON.stringify(data));
                  done();
                }
            );*/
            
           
        } catch (err) {
            console.error('Caught Error: ', error);
            done();
        }
    }
    
    


  • That is lot of code for me to check in limited time. It would be much easier if it is just about 10 lines explaining the problem...

    It general the done function should be called just once. This way you tell to scripts runtime that your async work is done.
    If you pass an error to the done call, it fails the whole request.

    If you need to make two async requests. One option is to make one and in its callback call another one. You should call done only after the second one is finished and you get callback for it. So for you one option is to call the second request inside the callback of the first one. The same as you do for token. Just one level deeper. Of course you can call both in parallel and use another property to find out if you are really done or not. Or you external library like async.

    Maybe check some sources for "javascript or nodejs callbacks". There is no jsreport magic or extra knowledge needed to make this working.



  • Hi Jan,

    that's exactly what I've tried as well, to call the request in a callback function but that didn't work either. Neither relying on the property if it's been fulfilled, but all of them end with ECONNRESET. I'll try other version of jsreport where you can pass back the promise.

    Thanks



  • it turned out to be the proxy and the nature of the requests (cloud vs internal) and with the proxied request to the internal one it was screwing things up. mea culpa. Apologies.


Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.