Код-ревью Middle Ошибки и логирование обновлено

Код-ревью: обработка ошибок в сервисе

Вопрос

Фрагменты обработки ошибок из Node-сервиса. Найди, что приведёт к потере ошибок, падению или некорректной работе.

process.on('uncaughtException', (err) => {
  console.log('error', err);
});

async function loadUser(id) {
  try {
    return await db.users.find(id);
  } catch (e) {
    console.log(e);
  }
}

async function charge(order) {
  try {
    await payments.charge(order);
  } catch (e) {
    throw new Error('Payment failed');
  }
}

function readConfig() {
  fs.readFile('config.json', (err, data) => {
    if (err) throw err;
    config = JSON.parse(data);
  });
}

Коротко

Разделяем ошибки на операционные (сеть, таймаут, нет файла: ожидаемы, обрабатываем) и программные (баг: undefined is not a function). Программные не лечатся в рантайме: правильная реакция на uncaughtException и unhandledRejection это лог и выход с ненулевым кодом, рестарт сделает оркестратор.

Что должен найти ревьюер

  1. Ошибкастрока 1
    После uncaughtException процесс в неопределённом состоянии; его надо залогировать и завершить (process.exit(1)), чтобы оркестратор перезапустил. Продолжать работу опасно.
  2. Стильстрока 2
    console.log вместо структурного логгера с уровнем error: ошибку не найдут по уровню и не построят алерт.
  3. Ошибкастрока 9
    Ошибка проглатывается, функция возвращает undefined: вызывающий решит, что пользователя нет (404 вместо 500), сбой БД станет невидимым.
  4. Ошибкастрока 17
    Исходная причина теряется: нужен new Error(..., { cause: e }), иначе при разборе инцидента непонятно, отказ банка это, таймаут или баг.
  5. Ошибкастрока 23
    throw внутри колбэка не ловится ни вызывающим кодом, ни try/catch: это uncaughtException. Нужен промис-API fs.promises.readFile с обработкой.
  6. Ошибкастрока 24
    JSON.parse битого конфига тоже бросит в колбэке; и config пишется в неявную глобальную переменную, а читающий код может обратиться к ней до загрузки.

Разбор

Разделяем ошибки на операционные (сеть, таймаут, нет файла: ожидаемы, обрабатываем) и программные (баг: undefined is not a function). Программные не лечатся в рантайме: правильная реакция на uncaughtException и unhandledRejection это лог и выход с ненулевым кодом, рестарт сделает оркестратор.

Антипаттерны в коде: проглатывание (catch с одним console.log), подмена ошибки без cause, throw из колбэка, где его некому поймать. Конфиг читают синхронно на старте (это нормально, сервис ещё не обслуживает запросы) и валидируют схемой: упасть на старте с понятной ошибкой лучше, чем через час на первом обращении.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.