У меня есть стек для создания докеров с несколькими контейнерами.Этими двумя являются расширенный контейнер python:3-onbuild
(см. Базовое изображение здесь ) с запущенным веб-сервером falcon и базовый контейнер node:8.11-alpine
, который пытается отправлять запросы на веб-сервер python.Веб-сервер python выполняет вызовы из базы данных в контейнер postgres:alpine
.Это упрощенная версия моего docker-compose.yml
файла:
version: '3.6'
services:
app: # python:3-onbuild
ports:
- 5000
build:
context: ../../
dockerfile: infra/docker/app.Dockerfile
lambda: # node:8.11-alpine
ports:
- 10000
build:
context: ../../
dockerfile: infra/docker/lambda.Dockerfile
depends_on:
- app
db: # postgres:alpine
ports:
- 5432:5432
build:
context: ../../
dockerfile: infra/docker/db.Dockerfile
У меня есть набор интеграционных тестов, которые я пытаюсь пройти.Когда я запускаю тесты с конечной точкой во внешнем мире (сервер Python https, работающий с тем же кодом, что и служба app
), все тесты проходят.Проблема возникает, когда я пытаюсь сделать эти запросы к службе app
из моего стека docker-compose
, в частности от службы lambda
к службе app
.
Я так не думаюэто проблема времени.В функции beforeAll
моего набора jest я опрашиваю сервер python в течение 100 секунд, один раз каждые 10 секунд, например:
В моем тесте jest
beforeAll(async () => {
const endpointUrl = getEndpointUrl();
const status = await checkStatus(endpointUrl, 10);
// NOTE: never reaches this line, starts tests before 5-minute timeout
console.log(`[integration.test]: status = ${status}`);
}, 5 * 60 * 1000); // 5-minute timeout for async function
Где checkStatus()
определяется
/**
* Checks the status of the backend every 10 seconds, n times
* @param {string} endpointUrl
* @param {number} n
*/
export function checkStatus(endpointUrl: string, n: number): Promise<string> {
console.log(`[lib][checkStatus]: before timeout date = ${Date()}`);
return new Promise<string>((resolve, reject) => {
checkStatusHelper(endpointUrl, n, resolve, reject);
});
}
function checkStatusHelper(endpointUrl, n, resolve, reject): void {
if (n === 0) reject();
setTimeout(() => {
console.log(`[lib][checkStatus]: after timeout date ${n} = ${Date()}`);
rp.get(`${endpointUrl}/status`)
.then(res => {
console.log(`[lib][checkStatus]: after request date = ${Date()}`);
console.log(`[lib][checkStatus]: res = ${res}`);
resolve('success');
})
.catch(err => {
console.log(`[lib][checkStatus]: err = ${err}`);
checkStatusHelper(endpointUrl, n - 1, resolve, reject);
});
}, 10 * 1000);
}
Я получаю вывод, подобный следующему (с request-promise-native
):
console.log src/lib.ts:30
[lib][checkStatus]: before timeout date = Fri May 11 2018 01:54:10 GMT+0000 (UTC)
console.log src/lib.ts:39
[lib][checkStatus]: after timeout date 10 = Fri May 11 2018 01:54:20 GMT+0000 (UTC)
console.log src/lib.ts:47
[lib][checkStatus]: err = RequestError: Error: getaddrinfo ENOTFOUND app app:5000
console.log src/lib.ts:39
[lib][checkStatus]: after timeout date 9 = Fri May 11 2018 01:54:31 GMT+0000 (UTC)
console.log src/lib.ts:47
[lib][checkStatus]: err = RequestError: Error: getaddrinfo ENOTFOUND app app:5000
# etc ...
И аналогичный вывод с axios
вместо request-promise-native
console.log src/lib.ts:30
[lib][checkStatus]: before timeout date = Fri May 11 2018 01:56:57 GMT+0000 (UTC)
console.log src/lib.ts:39
[lib][checkStatus]: after timeout date 10 = Fri May 11 2018 01:57:07 GMT+0000 (UTC)
console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: getaddrinfo ENOTFOUND app app:5000
at Object.dispatchError (/Halloo/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Halloo/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at emitOne (events.js:121:20)
at Request.emit (events.js:211:7)
at Request.onRequestError (/Halloo/node_modules/request/request.js:878:8)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at Socket.socketErrorListener (_http_client.js:387:9)
at emitOne (events.js:116:13)
at Socket.emit (events.js:211:7) undefined
console.log src/lib.ts:47
[lib][checkStatus]: err = Error: Network Error
console.log src/lib.ts:39
[lib][checkStatus]: after timeout date 9 = Fri May 11 2018 01:57:18 GMT+0000 (UTC)
console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: getaddrinfo ENOTFOUND app app:5000
at Object.dispatchError (/Halloo/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Halloo/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at emitOne (events.js:121:20)
at Request.emit (events.js:211:7)
at Request.onRequestError (/Halloo/node_modules/request/request.js:878:8)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at Socket.socketErrorListener (_http_client.js:387:9)
at emitOne (events.js:116:13)
at Socket.emit (events.js:211:7) undefined
console.log src/lib.ts:47
[lib][checkStatus]: err = Error: Network Error
# etc ...
Я также не думаю, что это не проблема сети.Если я закомментирую свой тестовый шаг и позволю сервису lambda
нормально развернуться, я могу зайти в lambda-контейнер и проверить соединение, используя axios
или request-promise-native
.Эта конечная точка /status
просто возвращает все имена таблиц в моей базе данных, чтобы убедиться, что контейнер базы данных также работает правильно.Это работает почти мгновенно, и гораздо раньше, чем за 100 секунд
$ node
> const axios = require('axios')
undefined
> axios.get('http://app:5000/status').then(res => console.log(res.data));
Promise {
<pending>,
domain:
Domain {
domain: null,
_events: { error: [Function: debugDomainError] },
_eventsCount: 1,
_maxListeners: undefined,
members: [] } }
> [ [ 'table0' ],
[ 'table1' ],
[ 'table2' ],
[ 'table3' ],
[ 'table4' ],
[ 'table5' ] ]
Я подумал, что, может быть, я не смогу использовать шутку для этих целей, но я чувствую, что могу, потому что все работает без нареканий, когда я изменяю URL своей продукции.Конечная точка https работает в aws и закомментируйте шаг beforeAll()
в моем наборе шуток.