openlang

ImportFailure создаётся в parse(), но до Main не доходит (получаю exit 3 вместо 2)

Здравствуйте,

Я сейчас между работами, так что у меня полно времени, чтобы разбираться в 100-строчной программе.

ledger-import читает CSV с разделителем «точка с запятой» и пишет очищенные строки в staging-файл. Ничего не должно оставаться в staging, если весь файл не разобран целиком. В моём тестовом файле data/march.csv на строке 4 битая сумма (-12,5x). Я ожидал import rejected: line 4: bad amount ... и код выхода 2. А получаю вот это, с кодом выхода 3:

SEVERE: staging problem: staging file build/staging.tmp closed with 2 uncommitted rows

Номера строки и плохого значения нигде нет. Если временно добавить System.err.println в catch-блок parse(), то оно печатается, то есть ImportFailure действительно создаётся. Просто в Main он не приходит. Когда я исправляю строку 4, импорт работает нормально.

Сначала я подозревал порядок catch в Main и настройку logging.properties. Перестановка двух catch-блоков ничего полезного не изменила. Вот соответствующие части:

// Importer.run()
StagingWriter writer = new StagingWriter(staging);
try {
    ...
    writer.add(parse(lineNo, line));
    ...
    writer.commit();
    return writer.count();
} finally {
    writer.close();
}
// StagingWriter.close()
out.close();
if (!committed && rows > 0) {
    Files.deleteIfExists(path);
    throw new IOException("staging file " + path + " closed with " + rows + " uncommitted rows");
}

Main сначала ловит ImportFailure (exit 2), потом IOException (exit 3).

Возможно ли, что проблема вообще не в логировании? Куда девается моё исключение?

Переведено с английскогоПоказать оригинал

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    Ваш ImportFailure не теряется в логировании. Его подменяет блок finally.

    parse() бросает ImportFailure. Затем finally запускает writer.close(). Строки не закоммичены, поэтому close() бросает IOException. Новое исключение, брошенное в finally, перебивает старое. ImportFailure отбрасывается, и Main видит только IOException. Поэтому у вас и exit 3.

    Чинится через try-with-resources. Если тело бросает исключение, то исключение из close() добавляется как suppressed, а исходное остаётся основным:

    try (StagingWriter writer = new StagingWriter(staging)) {
        ...
        writer.commit();
        return writer.count();
    }

    StagingWriter должен реализовывать AutoCloseable. И в перспективе вынесите проверку «uncommitted» из close(). Отдельный abort-путь, который просто удаляет файл, получится чище.

    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. `String::from_utf8` при неудаче возвращает байты

    API, которое забирает значение, должно решить, что с ним будет при неудаче. String::from_utf8 принимает Vec<u8> по значению,…

    Ответы 0Последняя активность rust
  2. except ValueError никогда не срабатывает вокруг gather(return_exceptions=True), а потом TypeError на ValueError

    Перед созвонами с клиентами я запускаю небольшой скрипт, который оценивает сайт каждого клиента по трём метрикам, с весами дл…

    Ответы 5Последняя активность python
  3. `result.map_error` в каждой строке цепочки use

    use вместе с result.try - моя любимая часть Gleam, и я начинаю на неё немного злиться. Каждый шаг вызывает другой модуль, у к…

    Ответы 1Последняя активность gleam