I am trying to increase the timeout time of my React app. I am using axios, so initially I tried:
axios.post('/gene_info', postData, {timeout: timeoutVal});
It did not work, and there is the respective thread that deals with it:
https://github.com/axios/axios/issues/647
So, I tried the following code:
let CancelToken = axios.CancelToken;
const source = CancelToken.source();
try {
let response = null;
setTimeout(() => {
if (response === null) {
source.cancel();
}
}, 60 * 1500 * 1000);
response = await axios.post('/gene_info', postData, {cancelToken: source.token});
console.log(response);
} catch (error) {
console.log(error);
}
And it is not working either. The request times out and I see the empty response error, even though on the Node.js backend I see that the result is returned correctly. On the backend I am making a very long running request to Neo4j database. I got a suspicion that maybe it timeouts, so I added to neo4j.config file the following lines:
unsupported.dbms.executiontime_limit.enabled=true
unsupported.dbms.executiontime_limit.time=99999999999999s
That I found here:
How to configure a query timeout in Neo4j 3.0.1
and restarted neo4j but it did not help either. Here is what I see in the terminal:
I am not sure what this POST /gene_info - - ms - - means, whether the problem is still on the front end, or the back end, but I have a suspicion that neo4j now times out, but it is still calculating the result which I see using console.log() statements. Any suggestions would be greatly appreciated.
Update
I tried using Reacts fetch, but still not working. Here is the code:
fetchWithTimeout = (url, postData, timeout) => {
let didTimeOut = false;
new Promise(function(resolve, reject) {
const timeout = setTimeout(function() {
didTimeOut = true;
reject(new Error('Request timed out'));
}, timeout);
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
timeout: timeout,
body: JSON.stringify(postData)
})
.then(function(response) {
// Clear the timeout as cleanup
clearTimeout(timeout);
if(!didTimeOut) {
console.log('fetch good! ', response);
resolve(response);
}
})
.catch(function(err) {
console.log('fetch failed! ', err);
// Rejection already happened with setTimeout
if(didTimeOut) return;
// Reject with error
reject(err);
});
})
.then(function() {
// Request success and no timeout
console.log('good promise, no timeout! ');
})
.catch(function(err) {
// Error: response error, request timeout or runtime error
console.log('promise error! ', err);
});
}
Then I am calling this function like that:
let postData = {"jsonData": geneNameArr,
"datasetName": this.props.datasetName};
this.fetchWithTimeout('/gene_info', postData, timeout).then((response) => {
console.log("fetchWithTimeout is done!");
console.log(response);
});
Update
I tried using axios.create() function with no success:
const axiosInstance = axios.create({
baseURL: '/gene_info',
timeout: timeout
});
axiosInstance.post('', postData).then((response) => {
console.log("axios request is done with create() method");
console.log(response);
});
If nothing seems to work on the front end, I would think it is the timeout that comes from the neo4j driver, even though somehow the results are returned. Here is the code I am using for the driver:
router.post('/gene_info', function(req, res) {
...
...
var driver = dbUtils.driver;
const session = driver.session();
session.run(
full_query,
{}
).then(result => {
const exprData = chartService.prepareGeneInfoData(result, '');
res.json({
exprData
});
session.close();
});
})
Or maybe it can also be express.Router(); that I am using for treating get and post requests on the backend with Node.js
If you want to configure your timeout in axios, you can use,
const axiosInstance = axios.create({
baseURL: "http://example.com/api/",
timeout: 5000
});
Replace 5000 with your timeout value needed.
Ultimately I found the solution that worked here:
Node Express specific timeout value per route
And I used the setConnectionTimeout() function in the following way:
router.post('/gene_info', setConnectionTimeout('12h'), function(req, res) {
...
})
Related
I am trying to chain three requests in one with Axios. I am practicing vue.js so please correct me if my approach is not ideal.
The goal is to have three requests. One is a post followed by 2 Gets. What I would like to achieve is one chained request.
My questions are:
Is this a good way to handle this? Should they be chained together like this?
Is it possible to map the response to a model like I did in the first post request and pass it to the next?
const apiClient: AxiosInstance = axios.create({
headers: {
'content-type': 'application/json',
'X-RapidAPI-Key': '08f852e........22fb3e2dc0...',
'X-RapidAPI-Host': 'judge0-ce.p.rapidapi.com'
},
params: {base64_encoded: 'true', fields: '*'},
});
export const api = {
async submitCode(code: Code) {
code.language_id = 60
code.stdin = "Sn..2Uw"
code.source_code = btoa(code.source_code)
apiClient.post<Token>(`https://judge0-ce.p.rapidapi.com/submissions?language_id=${code.language_id}&source_code=${code.source_code}&stdin=SnVkZ2Uw`)
.then(function (response) {
console.log("res.data", response.data.token);
}).then(function (token) {
console.log("token", token); // <---- empty
`https://judge0-ce.p.rapidapi.com/submissions/${token}` // <---- get request
}).then(function (response) {
console.log("res.data", response);
}).then(function (response ) {
// here I will need a model
})
.catch((err) => {
const error = err.response ? err.response.data : err;
console.log("error" + error);
})
}
}
You have to await each function if the next one is dependent on the previous. Or you could use Promise chaining in the traditional sense using new Promise(resolve, reject). Async only applies to top level, so you will need to declare subsequent functions 'async' again as shown.
I would also suggest setting axios defaults with a base URL so you don't have to repeat the full URL each time. Note that console.log statements are not "Thenable" so your 1st statement has no effect, nor does your 3rd, other than to define your next variable.
const apiClient = axios.create({
baseURL: 'https://judge0-ce.p.rapidapi.com/submissons',
// ... headers ... //
});
export const api = {
async submitCode(code){
// ... code variable ...//
await apiClient.post(
`?language_id=${code.language_id}&source_code=${code.source_code}&stdin=SnVkZ2Uw`)
.then(async (response1) => {
const token = response1.data.token
await api.get(`/${token}`)
}).then(async (response2) => {
console.log(response2.data)
const model = response2.data.map((val1) => apiClient.get(`anotherGet/${val1.id}`))
const result = await Promise.all(model)
return result.map((val2) => val2.data)
})
// ... catch ...//
}}
You useasync, then don't chain promices
async function submitCode(code: Code) {
code.language_id = 60
code.stdin = "Sn..2Uw"
code.source_code = btoa(code.source_code)
try { // ~ global `.catch`
const token = await apiClient.post<Token>(`https://blah`)
const get1result = await apiClient.get<Blah>(`https://balah?${token}`)
const get2result = await apiClient.get<Blah>(`https://balah?${token}`)
doBlah({token, get1result, get2result})
} catch (err) { // maybe should check object type here
const error = err.response ? err.response.data : err;
console.log("error" + error);
}
}
As for Vue, I can only recomment to use asyncComputed which you can feet Promise into if you need that
Express also had express.api or something with which you can skip https://blah/com/api/ part of url, check it
I'm trying to call an external API in Firebase Functions but i always get a timeout.
What can be the issue causing this?
Here is my code
exports.getCountryData = functions.https.onRequest((request, response) => {
const https = require('https');
const options = {
hostname: "api-football-v1.p.rapidapi.com/v3",
path: '/fixtures?next=5',
headers: {
"x-rapidapi-host": "api-football-v1.p.rapidapi.com/v3",
"x-rapidapi-key": "my-api-key"
}
};
var req = https.get(options, (resp) => {
let data = '';
resp.on('data', (chunk) => { data += chunk; });
resp.on('end', () => {
var result = JSON.parse(data);
console.log("Api fetched successfully");
console.log(result);
response.send({ fulfillmentText: result});
});
}).on("error", (err) => { console.log("Error: " + err.message); });
});
An event-driven function may fail to successfully complete due to errors thrown in the function code itself. Some of the reasons this might happen are as follows:
The function contains a bug and the runtime throws an exception.
The function cannot reach a service endpoint, or times out while
trying to reach the endpoint.
The function intentionally throws an exception (for example, when a
parameter fails validation).
When functions written in Node.js return a rejected promise or pass a
non-null value to a callback.
In any of the above cases, the function stops executing by default and the event is discarded. If you want to retry the function when an error occurs, you can change the default retry policy by setting the "retry on failure" property. This causes the event to be retried repeatedly for up to multiple days until the function successfully completes.
In this question, the service endpointi ‘api-football-v1.p.rapidapi.com/v3’ itself took so much time to load ( not reachable ), that was the issue. Changing the API endpoint to v3.football.api-sports.io and then calling the external API in Firebase Functions solved the issue for our user #tate_xy
It turns out using their Rapid Api url (api-football-v1.p.rapidapi.com/v3) was was resulting in a timeout. Using a direct Api url (v3.football.api-sports.io) with their domain name in it did the trick for me.
Here is my working code.
exports.getCountryData = functions.https.onRequest((request, response) => {
const https = require('https');
const options = {
hostname: "v3.football.api-sports.io",
path: '/fixtures?next=5',
headers: {
"x-rapidapi-host": "v3.football.api-sports.io",
"x-apisports-key": "my-api-key"
}
};
var req = https.get(options, (resp) => {
let data = '';
resp.on('data', (chunk) => { data += chunk; });
resp.on('end', () => {
var result = JSON.parse(data);
console.log("Api fetched successfully");
console.log(result);
response.send({ fulfillmentText: result});
});
}).on("error", (err) => { console.log("Error: " + err.message); });
});
I have a server application (we'll call ServerApp1) which is going to be running on an Azure VM instance. I have a separate server (which we'll call ServerApp2) on a different machine which will be communicating with ServerApp1 and a separate client. The Azure VM is going to be spun up and/or down depending on need, so it's quite possible that the VM (and thus ServerApp1) aren't even alive to respond to request from ServerApp2. My client is polling ServerApp2 to ask for the status of ServerApp1, but if the VM is currently down then that request hangs for like 20 seconds before issuing an error with code ETIMEDOUT. What I'd like is for ServerApp2 to make the request to ServerApp1 to see if it's alive, but after about 1 or 2 seconds of not getting a response to then simply stop and tell the client that's it's not currently running. I thought I could get away with adding a {timeout:2000} parameter to my axios call, but this doesn't seem to change the behavior in any noticeable way.
Here's the function that gets called when the client asks ServerApp2 what the status is of ServerApp1:
router.get('/getCurrentConsoleStatus', function(req, res) {
async function getStatus() {
try {
const result = await consoleDataService.getConsoleStatus();
if (result.message === 'Begin listen for job.') {
console.log('The app is ready!');
} else {
console.log('The console app is not ready');
}
} catch (error) {
console.log(`Error communicating with console app: ${error}`);
}
}
getStatus();
});
I have a function which creates the root Axios object:
var axios = require('axios');
module.exports = axios.create({
baseURL: 'baseURL',
timeout: 1000,
headers: {
'Content-type': 'application/json'
}
});
And then the function that gets called in consoleDataService.getConsoleStatus() looks like this:
exports.getConsoleStatus = async function() {
const res = await axios({
method: 'get',
url: '/status'
});
return res.data;
};
Thanks to #JonEdwards for the suggestion to use Promise.race. I ended up solving the issue with this function which tries to take the first promise which resolves first.
exports.getConsoleStatus = () => {
var sleep = function() {
return new Promise(resolve => {
setTimeout(function() {
resolve({ status: false });
}, 2000);
});
};
var fetch = async function() {
const res = await http({
method: 'get',
url: '/status'
});
return new Promise(resolve => {
resolve(res.data);
});
};
async function getStatus() {
const asyncFunctions = [sleep(), fetch()];
const result = await Promise.race(asyncFunctions);
return result;
}
return getStatus();
};
Tried through periodicSync but it doesn't work:
TypeError: Cannot read property 'register' of undefined
And this documentation says periodicSync not supported anywhere:
https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/periodicSync
Is it possible to implement this?:
self.addEventListener('activate', event => {
while (true) {
//timer 1 min
//POST query
}
});
And so that when the reopen browser requests keep on?
TypeError: Cannot read property 'register' of undefined
This error isn't related to periodicSync it's related to registration of Service Worker.
So a more systematic approach that is cross-browser would use the fetch API https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
To do it
self.addEventListener('THE_EVENT_TO_BE_USED', event => {
setInterval(function() {
try {
const url = 'https://randomuser.me/api';
// The data we are going to send in our request
let data = {
name: 'Sara'
}
// The parameters we are gonna pass to the fetch function
let fetchData = {
method: 'POST',
body: data,
headers: new Headers()
}
const registration = await navigator.serviceWorker.ready;
registration.backgroundFetch.fetch(url, fetchData).then(function(data) {
// Handle response you get from the server
}).catch(function(error) {
// If there is any error you will catch them here
});
} catch (err) {
console.error(err);
}
}, 60000);
});
So I am implementing axios call cancelation in the project. Right now looking at axios documentation it seems pretty straight forward https://github.com/axios/axios#cancellation
So I did define variables on the top of my Vue component like
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
obviously on top of that is import axios from 'axios';
Then I have a method of fetching the API
On the top of the method I want to cancel out the request in case it is running so the last one cancels out if the user spams the filtering.
async fetchPartners(inputToClear) {
source.cancel();
...
try {
const response = await axios.get(`../partners?limit=1000${this.createRequestString()}`, {
cancelToken: source.token
});
// Here you can see I did add the cancelToken to the request
this.partners = response.data.data;
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
const fetchErrors = this.utilGlobalHandleErrorMessages(error);
this.utilGlobalDisplayMessage(fetchErrors.message, { type: 'error' });
return [];
} finally {
...
}
},
So it is pretty straight forward, just took the code from axios documentation I gave you above, it should be working by logic. But what is actually happening, it doesn't even allow me to fetch the call, it is already cancelled out before I can call it. On console it shows me
Request canceled undefined
It just catches the error as if I am cancelling the call, but how can it be, because I am source.cancel() before the call.
Anyone has any idea?
I hope you should throttle your requests instead of canceling the request.
Could you please try the following if throttle does not suit your requirement?
const CancelToken = axios.CancelToken;
let source;
async fetchPartners(inputToClear) {
if(source){
source.cancel();
}
...
source = CancelToken.source();
try {
const response = await axios.get(`../partners?limit=1000${this.createRequestString()}`, {
cancelToken: source.token
});
// Here you can see I did add the cancelToken to the request
this.partners = response.data.data;
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
const fetchErrors = this.utilGlobalHandleErrorMessages(error);
this.utilGlobalDisplayMessage(fetchErrors.message, {
type: 'error'
});
return [];
} finally {
...
}
}