Комментарии 18
возможно, что ошибка совсем не в вашем коде, а в сторонней библиотеке

Э, ну мы как-то после полугода разборок, смены трех или четырех версий Java, дорылись силами поддержки Оракла и своими до бага в ядре линукс. Типа, Один из вариантов mutex плохо работал.
НЛО прилетело и опубликовало эту надпись здесь
Не понял из текста.
Почему нельзя было воспроизвести у себя и посмотреть?

Потому что данный тип исключения с циклической ссылкой генерировался библиотекой Apache VFS в очень специфическом случае — когда upload файла фейлился на OutputStream.close(). В остальных случаях, когда соединение рвалось на OutputStream.write(), в т.ч. и на интеграционных тестах, все отрабатывало без проблем. В то время у клиента по ночам возникали проблемы с инфраструктурой, и данный баг время от времени редко, но вылезал.

Так баг-то, по вашему, в Logback или в Apache VFS?

(по моему – в Apache VFS, но хорошо было бы увидеть исправление в нём и защиту от таких багов в Logback)

Если глобально, то в дизайне IO-стримов в Java. А конкретно этом случае виноват Logback. В Java нигде не говорится, что циклические ссылки невозможны или некорректны. Она не дает создать только прямую ссылку на само исключение через ex.addSuppressed(ex), а транзитивные возможны. К тому же остальные логгеры отрабатывают корректно.


Apache VFS в случае, если рвалась сессия SFTP, кешировал это исключение и кидал его на все последующие вызовы write(), что впринципе корректно. Но поскольку в close() Apache VFS еще производил запись (типа установить атрибуты удаленного файла), то в случае ошибки блок try-with-resources добавлял к suppressed то же самое закешированное исключение, что вызывало цикличность. Как-то так.


P.S. Вот Apache VFS реально плохо задизайнена. Там дофига подводных камней, один из которых — привязка ресурсов к ThreadLocal. То есть если вы открываете ресурс в одном треде, пишите или закрываете в другом, то у вас происходит утечка памяти, которая в нашем случае стабильно приводила к OutOfMemoryError.

Страшные вещи вы рассказываете…
Привязку ресурсов к треду я ещё могу понять (если это задокументировано), а вот кэширование и повторное использование exceptions за пределами моих представлений о добре и зле.

Из подобных мистических историй но уровнем загадочности полегче припомнилось:
Задача планировщика так же останавливалась в try-catch блоке, при этом проходя мимо всех catch и finally. Но здесь было проще догадаться: как оказалось, задача где-то у себя очень глубоко (где не ожидалось) открывала http соединение, и вечно ждало ответа, хотя физически соединение было прервано (даже от сети отключали, исключение не выпадало)


Ещё более лёгкая на догадки проблема была связана с некорректной велосипедной реализацией пула в части синхронизации, ошибка похожая на ленивый синглтон в котором отсутствует блок синхронизации, в результате которой утекали зомби, оставшиеся без нужных ссылок (случайно заменены заместителями делающими их работу), ничего не делающие, но висящие в памяти и активно мешающие.

А по топику: это не просто баг, это "удачный" союз двух багов, и я даже не знаю, какой из них более некорректный — рекурсивный стектрейс или не ожидание рекурсии в этом моменте.
Но, имхо, давно висящий тикет для библиотеки такого уровня, при предположении, что ситуация там не авральная — это халатность

Да можно подумать сторонние библиотеки пишут единороги с крыльями…
Разбираясь в коде jdbc thin драйвере Oracle просто поражался степени лапшеватости и корявости его кода.
jdbc драйвер кидал пустое(!) RuntimeException при возникновении проблем маппинга структур java на структуры Oracle.
Всегда нужно быть готовым к подобным проблемам.

Давно делал workaround-ы для различных кривых оракловых инфраструктурных утилит. В том числе декомпилировал и встраивал свой код. Степень криворукости оракловых программистов поражает воображение. Иногда тратил слишком много времени на попытки докопаться и доработку просто отменяли.
Мы однажды столкнулись с тем, что Hibernate генерировал синтаксически некорректный SQL для Oracle (там как-то смешивались оракловый JOIN с плюсиком и классический JOIN, точно уже не помню). Несколько месяцев пришлось держать свой форк, пока наш патч в апстрим не приняли.

Хибернейт у меня до сих пор оставляет некий осадок от использования. И некорректный sql тоже был. Из недавнего — в тестах, когда тест запускается внутри одной единственной транзакции с Rollback аннотацией над тестовым методом при транзакционной вложенности в тестируемых сервисах хибернейт теряет дочерние сущности. Вроде как и баг хибернейта, но руки не дошли докопаться до истины

У меня тоже с хибернейтом не сложилось. Известны случаи, где он генерит семантически неправильный SQL, иногда делает странные сторонние вещи, когда его не просят, причем в зависимости от движка базы, до последнего времени криво поддерживал EntityGraph, и после перехода на ByteBuddy стал неимоверно долго стартовать. Поэтому я уже привык использовать EclipseLink.

А я не так давно собственноручно раскопал баг с 100% CPU при использовании Selector.select() в Android.
Но как оказалось, до меня уже раскопали.
www.saschahlusiak.de/2018/10/selector-select-returns-0-immediately

Печаль в том, что этот баг находится в sun.nio.ch.PollSelectorImpl Java 8, и Android его не особо спешить исправить…
Данная баг фича все еще присутствует в последней версии библиотеки.

Лицензия свободная. Так, исправьте и сделайте PR, кто вам мешает?

Что мешает?
Ну вот например: планировщик заданий «enterprise» (как они себя называют) уровня.
github.com/quartz-scheduler/quartz/issues
176 issues (225 закрыто)
38 висящих пулл-реквестов
28 contributor-ов
Последний релиз — год назад.
При активной эксплуатации нашёлся редкий баг, и вряд ли кто будет его чинить — у всех-то нормально работает.

В учебных заведениях нужно доносить мысль, что open-source — это не «бесплатно скачал и пользуйся», а никто ничего тебе не должен. И при выборе библиотеки нужно взвешивать затраты между поддерживаемым платным ПО и затратами на самостоятельное допиливание «бесплатного» ПО.

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