Обещание не разрешается после завершения соединения - PullRequest
0 голосов
/ 17 января 2020

У меня есть функция mon goose connect, в которой я пытаюсь дождаться повторного подключения, если первая попытка не удалась:

async connect() {
    const options = {...}
    try {
        console.log("starting")
        await this._connectWithRetry(options)
        console.log("finished")
    } catch (err) {
        winston.error(`Could not connect to Mongo with error: ${err}`)
    }
}

private async _connectWithRetry(options) {
    return new Promise( async (resolve, reject) => {
        try {
            winston.info("Connecting to mongo...")
            await mongoose.connect(this.dbURI, options)
            winston.info("Connection successful.")
            resolve()
        } catch (err) {
            winston.info("Failed to connect to mongo. Retrying in 5 seconds...")
            setTimeout( async () => {
                await this._connectWithRetry(options)
            }, 5000)
        }
    })
}

Она успешно ждет, пока я подключусь. Но как только я подключаюсь, вторая консольная линия не удаляется («закончена»). поэтому я полагаю, что мое обещание разрешено с ошибками. Что я делаю не так?

1 Ответ

0 голосов
/ 18 января 2020

Ваш код «работает», если соединение с БД устанавливается впервые.

Если используется механизм повтора, вы увидите описанную ошибку.

Promise создается при первом вызове mongoDBConnect никогда не разрешается в пути выполнения повторных попыток.

Это происходит потому, что последующие вызовы mongoDBConnect выполняются в совершенно отдельном контексте выполнения в будущем тике события l oop, управляемый setTimeout - и каждый вызов создает новую Promise, полностью отключенную от вашей connect функции.

Этот рефакторинг должен решить проблему:

const delay = (interval) => new Promise(resolve => setTimeout(resolve, interval))

async connect() {
    const options = {...}
    try {
        console.log("starting")
        await this._connectWithRetry(options)
        console.log("finished")
    } catch (err) {
        winston.error(`Could not connect to Mongo with error: ${err}`)
    }
}

private async _connectWithRetry(options) {
    try {
        winston.info("Connecting to mongo...")
        await mongoose.connect(this.dbURI, options)
        winston.info("Connection successful.")
    } catch (err) {
        winston.info("Failed to connect to mongo. Retrying in 5 seconds...")
        await delay(5000)
        await this._connectWithRetry(options)
    }
}

Испытательный жгут:

let retryCount = 0

const mongoose = {
    connect: ()=>retryCount++ === 2 ? Promise.resolve() : Promise.reject('fake error')
}

async function connect() {
    try {
        console.log("starting")
        await connectWithRetry()
        console.log("finished")
    } catch (err) {
        console.error(`connect error`, err)
    }
}

async function connectWithRetry() {
    try {
        console.log("Connecting to mongo...")
        await mongoose.connect()
        console.log("Connection successful.")
    } catch (err) {
        console.log("Retrying in 1 second...", err)
        await delay(1000)
        await connectWithRetry()
    }
}

const delay = (interval) => new Promise(resolve => setTimeout(resolve, interval))

connect()
...