Abort elasticsearch request using elastic.js - javascript

Is there a way to cancel requests/queries to Elasticsearch using elasticjs? The web app I am working on performs a request/query every 5 seconds, but I would like to cancel the request if for some reason the response doesn't show up in 5 seconds (so the browser doesn't pile up a bunch of requests that are unnecessary since the queries are happening repeatedly). I understand this would not prevent Elasticsearch from completing the query, but I would like to at least cancel the request in the browser.
Example:
var request = ejs.Request().doSearch();
var dataFromElasticsearch;
request.then(function (data) {
dataFromElasticsearch = data;
});
setTimeout(function () {
if (!dataFromElasticsearch) {
//do something here to cancel request
}
}, 5000)

Per documentation for elasticsearch.js (3.1, at the time of writing):
...calling the API will return an object (either a promise or just a plain object) which has an abort() method. Calling that abort method ends the HTTP request, but it will not end the work Elasticsearch is doing.
Specifically for your example:
setTimeout(function () {
if (!dataFromElasticsearch) {
request.abort();
}
}, 5000)

Related

Execute A Function When All xmlHttpRequests Are Complete

BRIEF
I have a website which gets data from an API. So it makes some post and get requests to a server once the website is opened. Let us assume it makes 5 different xmlHttpRequests as soon as the page loads but we cannot exactly know the time each call takes from start to finish.
FOR EXAMPLE
Call to one endpoint takes 2 seconds to complete and the other one takes 1 second to complete. So that means after 2 seconds both the calls are said to be finished.
TO-DO
I want to execute a function after all the xmlHttpRequests are complete because I am using window.performance.getEntries() to fetch all the requests initiated by the webpage and send it to my server as I am doing a web analytics project in which I need to access the times taken by each network request and convert the data into a chart.
EXTRA-QUESTION OR HINT
Is there any event that can be attached to the window as shown below to listen for all the network calls and execute my piece of code when all are finished.
window.addEventListener("load", function (event) {
//execute some code here
}
In the load event I am not able to capture all the requests by using performance.getEntries() because load fires before the ajax calls are finished.
As shown above I ask. Is there any trick or any event or anything in JavaScript by which we can wait untill all the XMLHTTPREQUESTS are finished and then execute some code.
WORKING SOLUTION
We can track browser AJAX calls using the code below :
const ajaxCallStatus = () => {
window.ajaxCalls = 0; // initial ajax calls
window.ajaxEndpoints = []; // keeping track of all ajax call urls (endpoints)
const origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
window.ajaxCalls++;
this.addEventListener('load', (event) => {
if (!window.ajaxEndpoints.includes(event['currentTarget'].responseURL)) {
window.ajaxEndpoints.push(event['currentTarget'].responseURL);
}
window.ajaxCalls--;
switch (window.ajaxCalls) {
case 0: // when ajax calls finish this runs
addData(window.ajaxEndpoints);
break;
}
});
origOpen.apply(this, arguments);
}
}
ADD DATA FUNCTION - Used for sending data to some backend.
function addData(arr, origOpen) {
XMLHttpRequest.prototype.open = origOpen;
axios.post('url', data)
.then((res) => console.log(res))
.catch((err) => console.log(err));
}
I would suggest you to wrap your requests in promises and then use Promise.all(...) like so:
const makeRequest = () => {
return new Promise((resolve, reject) => {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
resolve(xhttp.responseText); // On success, resolve the promise
} else {
reject(); // On failure, reject it
}
};
xhttp.open("GET", "filename", true); // Needs to be set to your needs. This is just an example
xhttp.send();
});
}
// This waits until all promises are resolved
const [result1, result2] = await Promise.all(makeRequest(), makeRequest());
// do stuff here with your results
console.log(result1);
console.log(result2);
PS: Basic Ajax example is from here, but just swap it for yours and create parameters or similar to make the requests you actually need
OR
You could use a library like Axios for Ajax requests, which already returns Promises by default. Check it out here: https://github.com/axios/axios

How can I tell when a loop is done.using JavaScript and Vue and AXIOS

I have a dataGrid from Syncfusion and I have a column of checkboxes. When I press a button the code reads all of the selected rows creates an array and loops until the process is ended.
this.selectedRecords = this.$refs.grid.ej2Instances.getSelectedRecords();
this.selectedRecords.forEach(function(arg, index) {
call HTTP API request. with AXIOS
get the return values and store it to the database
}
I could have 100+ rows selected and I need to be able to tell when all of the API calls are finished.
I have slowed down my calls so I only have a maximum of 10 calls per second using
axios.interceptors.request.use(
function(config) {
setTimeout(console.log("here request interceptor"), 100);
return config;
},
function(error) {
return Promise.reject(error);
}
);
And I have tried
if (self.selectedRecords.length - 1 === index) {
alert("Done");
}
but since there is not a guarantee that the rows are processed in order it can call "Done" too early.
I hope I've given you enough code to understand my problem without giving you too much to make it sloppy.
If I've understood correctly then you should just need to gather up the promises in an array and then use Promise.all to wait for them to all complete:
var requests = this.selectedRecords.map(function(arg, index) {
return axios.get(/* request details here */);
});
Promise.all(requests).then(function() {
console.log('Done')
});
If you need to process the individual requests using a then that's fine, just chain it on the end of the axios.get call:
return axios.get(/* request details here */)
.then(function(response) {
// Handle response
})
Update:
Request interceptors can return promises, which will be necessary if you want to hold up the execution of the request:
http.interceptors.request.use(function (config) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(config)
}, 5000)
})
})
Note that the example above is not performing proper throttling, it's merely delaying the request. It is purely to illustrate how promises can be used with interceptors. You haven't included the real interceptor in the question so I can't be more specific.

Non-block setTimeout for web server

I have a web server that upon request makes a phone call, waits 3 seconds and then checks if that phone call is still ongoing. I used setTimeout to integrate this but this blocks all other connections to the web server until the timeout has finished.
// example get request
app.get("/", function(req, res) {
// take an action
example.makeCall(function() {
setTimeout(function() {
// check the action
example.checkCall(function() {
res.status(200)
})
}, 3000)
})
})
Is there some other way of adding a timeout to a request without blocking all other incoming requests?
Not sure why your additional API requests are being blocked, new API requests should use a new invocation of your route's callback function on the call stack and shouldn't be dependant on previous callback functions finishing to be added to the call stack.
The issue might not be that the setTimeout is blocking and may be another problem such as your phone call API blocking new calls being made before a previous call has finished.
But something to try could be to wait 3 seconds in a promise to try to get around potential blocking.
function waitThree() {
return new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, 3000);
});
}
app.get("/", function(req, res) {
// take an action
example.makeCall(function() {
waitThree.then(function() {
example.checkCall(function() {
res.status(200)
});
});
})
});

Angular ngResource $save Method Clears $resource Object

Using Angular 1.5.5 here:
Is there any way to tell Angular to ignore response body for particular requests (such as $save)? It drives me crazy that after I call $save, angular updates the model with the object returned by a server, which initially was supposed to be used to distinguish between different resolutions of the request. It results in unwanted form clear. Interestingly enough, this behaviour remains even if I send a 400 or 500 http status code.
In case you need more info, relevant code is below.
Controller:
'use strict';
angular
.module('app.operators')
.controller('OperatorNewController', OperatorNewController);
OperatorNewController.$inject = ['operatorsService', 'notify'];
function OperatorNewController(operatorsService, notify) {
var vm = this;
vm.done = done;
activate();
function activate() {
vm.operator = new operatorsService();
}
function done(form) {
if (form.$invalid) {
// do stuff
return false;
}
vm.operator.$save(function(response) {
if (response.success && response._id) {
$state.go('app.operators.details', {id: response._id}, { reload: true });
} else if (response.inactive) {
// do stuff
} else {
// do other stuff
}
}, function (error) {
// do other stuff
});
}
}
Service:
'use strict';
angular
.module('app.operators')
.service('operatorsService', operatorsService);
operatorsService.$inject = ['$resource'];
function operatorsService($resource) {
return $resource('/operators/:id/', {id: '#_id'}, {
'update': { method: 'PUT' }
});
}
Server request handler is also fairly simple:
.post('/', function (req, res) {
if (!req.operator.active) {
return res.status(500).json({ inactive: true, success: false });
}
// do stuff
return res.json({ success: true });
});
In either way I don't like the idea of having to send the entire object from server (particularily when it's a failed request), and even if I have to, I still need a way to send some extra data that will be ignored by Angular.
Your help is very much appreciated!
The $save method of the resource object empties and replaces the object with the results of the XHR POST results. To avoid this, use the .save method of the operatorsService:
//vm.operator.$save(function(response) {
vm.newOperator = operatorsService.save(vm.operator, function(response),
if (response.success && response._id) {
$state.go('app.operators.details', {id: response._id}, { reload: true });
} else if (response.inactive) {
// do stuff
} else {
// do other stuff
}
}, function (error) {
// do other stuff
});
UPDATE
It results in unwanted form clear. Interestingly enough, this behaviour remains even if I send a 400 or 500 http status code.
This behavior is NOT VERIFIED.
I created a PLNKR to attempt to verify this behavior and found that the $save method does not replace the resource object if the server returns a status of 400 or 500. However it does empty and replace the resource object if the XHR status code is 200 (OK).
The DEMO on PLNKR
It drives me crazy that after I call $save, angular updates the model with the object returned by a server
It helps to understand how browsers handle traditional submits from forms.
The default operation for a submit button uses method=get. The browser appends the form inputs to the URL as query parameters and executes an HTTP GET operation with that URL. The browser then clears the window or frame and loads the results from the server.
The default operation for method=post is to serializes the inputs and place them in the body of an HTTP POST. The browser then clears the window or frame and loads the results from the server.
In AngularJS the form directive cancels the browser default operation and executes the Angular Expression set by either the ng-submit or ng-click directive. All $resource instance methods including $get and $save, empty and replace the resource object with XHR results from the server if the XHR is successful. This is consistent with the way browsers traditionally handle forms.
In RESTful APIs, HTTP GET operations return the state of a server resource without changing it. HTTP POST operations add a new resource state to the server. APIs usually return the new resource state, with additional information such as ID, Location, timestamps, etc. Some RESTful APIs return a redirect (status 302 or 303) in which case browsers transparently do an HTTP GET using the new location. (This helps to Solve the Double Submission Problem.)
When designing RESTful APIs, it is important to understand how traditional browsers behave and the expectations of RESTful clients such as AngularJS ngResource.

Async calls using AngularJS

We are making multiple HTTP requests using Angular:
$scope.GetTest1 = function () {
$http.get("/test/GetTest1/").success(function (response) {
$scope.res = response.aaData;
});
}
$scope.GetTest2 = function () {
$http.get("/test/GetTest2/").success(function (response) {
$scope.res = response.aaData;
});
}
$scope.GetTest3 = function () {
$http.get("/test/GetTest3/").success(function (response) {
$scope.res = response.aaData;
});
}
// This is called from an onclick of a button
$scope.LoadAll = function () {
$scope.GetTest1();
$scope.GetTest2();
$scope.GetTest3();
}
We assumed that these were all called async, however, we have log4net enabled and we log the datetime when the 'gets' are received, and the times for all 3 are:
19:05:26
19:05:27
19:05:28
This was an unexpected surprise as we assumed the time would all be within 1 second. ie async.
Not sure if we're missing something,
Sorry, question is, how do we make these async calls?
I suppose that the reason of that perhaps is on the server side. I had almost the same result when server could serve only one request from one client. If response from server fulfils your $http requests in one second then that could be a problem. Please check your network statistics and if you see that they were called simultaneously but were served not immediately then it's server side problem.
You can easily track this on browser's devtools' timeline

Categories

Resources