Description
Bug description
The connection is intermittently timing out when attempts are made to update the APIM using migrate.js.
The error occurs in various process here is an example error:
Unable to complete migration. Unable to complete import. Unable to generate the content. connect ETIMEDOUT
Reproduction steps
- Execute the script using:
node migrate
specifying the
--sourceSubscriptionId
--sourceResourceGroupName
--sourceServiceName
--destSubscriptionId
--destResourceGroupName
--destServiceName
Expected behavior
It is expected that the destination developer portal will be updated with the source portal code. Since it is random where the failure occurs one is not sure where the process will end.
Is self-hosted portal?
Yes
Release tag or commit SHA (if using self-hosted version)
Release 2.30.0
API Management service name
Environment
- Operating system: Windows 10 Build 19045
Additional context
I was able to resolve the issue by setting the timeout to two minutes
const options = {
port: 443,
method: method,
headers: headers,
timeout: 120000, // 2-minute timeout in milliseconds
};
and adding and a retryfunction, function
async sendRetryRequest(method, url, body, process = "") {
const maxRetries = 4; // Retry every 10 seconds for 1 minute
const retryDelay = 10000; // Retry delay in milliseconds (10 seconds)
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await this.httpClient.sendRequest(method, url, body);
return result;
} catch (error) {
console.log(`Process: ${process}`);
console.log(url);
console.log(
`Attempt ${attempt} out of ${maxRetries} failed:`,
error.message
);
if (attempt < maxRetries) {
console.log(`Retrying in ${retryDelay / 1000} seconds...`);
await new Promise((resolve) => setTimeout(resolve, retryDelay));
} else {
console.error(`Max retries reached of ${maxRetries}. Failing.`);
throw error;
}
}
}
}
example call: (I add an additional parm to tell me which function was being retired)
async getContentTypes() {
try {
const data = await this.sendRetryRequest(
"GET",
`/contentTypes`,
null,
"getContentTypes"
);
const contentTypes = data.value.map((x) =>
x.id.replace("/contentTypes/", "")
);
return contentTypes;
} catch (error) {
throw new Error(`Unable to fetch content types. ${error.message}`);
}
}