« first day (795 days earlier)      last day (2236 days later) » 

5:40 PM
@VladD нет. я сегодня и так пол дня переписываю код, который я написал 3700+ дней назад.
 
@PashaPash Сочувствую.
 
@VladD причем код хороший. но ведет себя нехорошо из-за каких-то внутренних изменений в .net фреймворке, на которые я тогда неумышенно завязался
будь ты проклят, 4.6.2!
 
@PashaPash Хм. А что там опасного? У нас вроде переход гладко прошёл.
 
@VladD он гладко прошел, но где-то глубоко внутри, в драйвере sql server появился багчек на работу из нескольких потоков. а в старом коде вызывался transaction.Rollback из кастомого энлистмента в TransactionScope. он, внезапно, вызывает его на потоке из пула. кастомный энлистмент нужен для того, чтобы избежать повышения транзакции до распределенной при открытии двух соединений в рамках одного TransactionScope (до 3.5 такое происходило даже если соединения открывались к одной базе).
и вот багчек убивает соединение, причем физическое. дотнет этого не замечае, и возвращает битое соединение в пул. оно оттуда достается, не падает на вызове begin tran, но падает на реальной команде. возвращается в пулл, гото 10
@VladD и мы имеем 40 минутный даунтайм после года 100% аптайма
99,97%, чтоб его
 
@PashaPash Ох. А вы намылили шею тестерам?
 
5:46 PM
@VladD на тестовом окружении не падало. точнее, там таймаут нереально долгий
 
@PashaPash То есть для меня работа с базой не из одного потока выглядела бы подозрительно в любом случае. :-\
 
@VladD ну она там неявно из одного потока. прошла незамеченной. и в 4.5 работало
 
Но я не спец по базам данных
@PashaPash А, то есть в коде нового потока (Task.Run) нет?
 
@VladD т.е. может быть даже это не 4.6.2. судя по всему, это именно azure sql стал по-другому рвать соединения при этом багчеке
@VladD нет. в коде есть реализация энлистмента (регистрации в транзакции), и у энлистмента есть метод Rollback
@VladD который реализован как this.transaction.Rollback() + проверки на null
 
@PashaPash Понял, а кто дёргает новый поток?
Ваш код или фреймворк?
 
5:50 PM
@VladD системный TransactionScope (точнее, что-то в дебрях System.Transactions), там есть хитрый механизим
 
@PashaPash Тогда ой. :-\
@PashaPash И как вы это пофиксили?
 
@VladD причем для родного (фремворского) SqlConnection все это выглядит очень хитро, там пачка локов и internal убиваний соединения внутри. т.е. он может убить из левого потока, а мы - нет
 
@PashaPash Фреймворки под капотом обычно достаточно грязные :)
 
@VladD пока - вставили костыль на симптом (из пула досталось битое соединение, и при попытке выполнить команду оно кинуло исключение, вписали в код для ретрая чистку пула) + вписали код для ретрая костыль, что если работали на живом соединении, и оно умерло с той ошибкой, которая выстреливает при чистке пула - ретрайнуть. общий код ретрая уже был, он на азуре обязателен
 
@PashaPash То есть получается какая-то фигня, System.Transactions не договорился с Azure SQL?
 
5:53 PM
@VladD договорился. они не дергают физический connection в левом потоке. они хитрыми хаками валидно прерывают текущий запрос (который делается в другом потоке)
 
@PashaPash А где ж тогда корень проблемы? У кого косяк в конечном итоге?
 
@VladD скорее, там Azure SQL не договорился с логикой "можно ли вернуть соединение в пул" - т.е. к пул попадает мертвое соединение
@VladD корень в том, что наш код обращался к соединению из потока, который System.Transactions запускает для "кастомных" регистраций ресурсов. т.е. они не знали, что это регистрация для SQL
@VladD а код в кастомной регистрации никак не может корректно прервать выполнение команды (просто потому, что фреймворковский SqlConnection не предоставляет для этого интерфейса)
 
@PashaPash А, вот оно что. Теперь понимаю. В общем, что можно и что нельзя делать на данном коллбеке?
 
@VladD ну, вобщем, с соединением - ничего нельзя
@VladD так что мы решили что фиг с ним, с System.Transactions
 
@PashaPash Понятно. Ну, это то, за что senior'ы получают senior'скую зарплату.
 
5:57 PM
@VladD будет самописный скоуп. с блекджеком и async local
 
@PashaPash Ого!
А смаршаллировать вызов в нужный поток не получалось? Или это нельзя из-за «чтобы избежать повышения транзакции до распределенной»?
 
@VladD просто за 10 лет у нас чуть поменялась инфраструктура, и тепер мы вынуждены в рамках одной транзакции работать с несколькими базами (но держать транзакцию только к одной). А System.Transactions не умеет это делать без плясок с бубном и кучи кода
@VladD нужный поток в это время ждет данных от SQL Server - т.к. он выполняет команду (которая таймаутналась)
 
@PashaPash А если заставить его сотрудничать? Пусть ждёт, но асинхронно?
Или там синхронный интерфейс?
(Ну ладно, не лезу в вашу архитектуру, сорри.)
 
@VladD без разницы. это просто нелегально. сам по себе SQL Server асинхронен, но есть ограничения на то, что можно делать именно параллельно
@VladD собственно, мы и получали ошибку типа "вы там слишком уж параллельно нашу параллельную обработку используете""
@VladD The server will drop the connection, because the client driver has sent multiple requests while the session is in single-user mode. This error occurs when a client sends a request to reset the connection while there are batches still running in the session, or when the client sends a request while the session is resetting a connection. Please contact the client driver vendor.
 
@PashaPash А, он даже параллельно не хочет? Это кисло как-то.
 
6:02 PM
@VladD он может вычитывать результаты нескольких запросов одновременно (режим марс), но не может одновременно выполнять сами запросы. т.е. нельзя ему скормить новый запрос пока он думает над предыдущим. как только данные пошли - уже можно
 
@PashaPash А, то есть он не отвечает, а вы даже закрыть соединение не имеете права?
 
@VladD закрыть - имеем. сказать "откати транзакцию" - нет
@VladD проблема только в том, что .net не дает взять и закрыть физическое соединение.
@VladD они их пулит и переиспользует. и вот такие "битые" соединения в пуле как раз и привели к лежанию всего
@VladD вобщем, забавная техническая заморочка, которая интересна только дотнет бэкендщикам
 
@PashaPash Ага, протекающий кэш получился.
 
ну я бы в такой ситуации вынес работу с БД в отдельный fork и потом кильнул бы жёстко всё это) да я костыли люблю)
 
56 messages moved from Stack Overflow на русском
 

« first day (795 days earlier)      last day (2236 days later) »