На стенде тестирования проводится функциональное тестирование и тестирование интеграций;
Он один на все команды или есть командные тестовые контуры? В первом случае когда одна из команд тестирует свой код, то все остальные волей-неволей тоже его тестируют, нарываясь на непонятные чужие баги?
Какое отношение имеют к основному тексту сноски State transition и Decision table в заключении?
На самом деле не такой уж он глобальный, а как раз весьма локальный, потому что включает/отключает эту фичу на конкретной схеме (тип Schema). Приложение может хостить сразу несколько схем, выставляя их наружу по разным урлам вроде ~/cats/graphql , ~/dogs/graphql . И вот по сути для каждой такой связки url+schema можно настраивать поведение. Короче говоря, флаг этот не статический, а экземплярный и живёт в каждой схеме.
Вообще странно, новый аккаунт работает (пока работает, со вчерашнего дня). Я специально не заполнял ничего в профиле. По идее если сейчас за что-то там можно зацепиться, то это либо IP, либо адрес почтового сервера, который при регистрации указывается. Почта на яндексе, ru домен.
Да, о "действовать радикально" странная какая-то логика. Забанили на гитхабе - идешь к Кремлю метать зажигательные смеси что ли? Логика железобетонная.
Меня затронула эта зараза. Сегодня. Я на хабре вообще крайне редко, но вот в поисках информации набрел на статью и решил поделиться опытом. На гитхабе с 2016 года, поддерживаю десяток проектов, а мониторю несколько десятков. На постоянной основе поддерживаю
Ессно, что убиваю на это дело прорву своего личного времени, сил и здоровья.
Первой реакцией было удивление и смех. Эдакое "нуемана, ну что же в творите, а"! Рабочий процесс выбили из под ног. Скоро релиз выпускать новой мажорной версии GraphQL движка и обвязки вокруг него, куча планов туда-сюда, а тут такое. И кто от этого потеряет? Смешно же, ну. У реп (Nuget пакетов, построенных из неё) миллионы скачиваний по всему миру. Пользуются сотни если не тысячи разработчиков. И теперь поддержка сего хозяйства местами будет буксовать, а местами встанет колом, доступы там получать надо некоторые, настройки делать. Белиберда.
Тикет им завел в поддержку. Там тоже посмеялся. Чтобы сделать тикет, нужно иметь аккаунт гитхаба. Завел другой аккаунт вот, почту под него завел. Залогинился в гитхаб (ура!) и сделал тикет. Надежды правда мало, что выйдет что-нибудь путное. И не известно, не заблокируют ли новый аккаунт.
Кстати говоря, интересно, на основании чего блокируют. История входов, где IP-адреса? Что-нибудь в профиле типа страны? Принадлежность к определенным конторам по указанным ссылкам в том же профиле? Вопросы, вопросы... Но суть одна - напакостили.
Но ничего, тут вопрос философский. Всегда надо давать возможность людям выстрелить себе в ногу, чтобы дать им понять, что из этого выходит. Отрицательный опыт - это тоже опыт.
Да, можно и так сказать, в этом суть. Ведь continueOnCapturedContext — эта та же самая привязка делегата к контексту, только окольным путем через вызов изнутри библиотеки. Ну и с возможными побочными эффектами для других методов, вызываемых внутри.
В самых простых случаях вы верно описали ситуацию. Добавлю от себя о вопросе необходимости задания continueOnCapturedContext. Реальность такова, что мы не используем библиотеки "атомарно". Как правило, выстроен целые стеки библиотек, эдакий слоеный пирог из функциональных слоев, где зачастую делегаты/события и прочие прелести передаются вверх и вниз по стеку вызовов. В таких ситуациях довольно сложно и накладно отслеживать, что кому нужно по контекстам синхронизации. Сейчас не нужно, в следующей версии библиотеки нужно. Невозможно, да и не стоит пытаться обременять вызывающие слои необходимостью задания continueOnCapturedContext. Да, в некоторых редкий ситуациях, особенно с легаси-кодом, вариант с continueOnCapturedContext может быть меньшим злом.
Такие случаи действительно есть. Я периодически с ними сталкивался. Бывает, что библиотека получает какой-то делегат, например, это может быть метод получения значения для какого-нибудь класса кеша. Так вот когда библиотека будет запускать этот делегат «в свободном контексте» через ConfigureAwait(false), то клиентский код будет падать на таких конструкциях как HttpContext.Current. Они будут равны null. Нужно сказать, что это было довольно давно, еще до использования .NET Core. В нём в этом плане стало удобнее и безопаснее, код практически был переписан с оглядкой на набитые шишки. Кстати тогда я действительно рассматривал вариант добавить параметр continueOnCapturedContext в библиотечный метод и вроде бы даже так и сделал, уже не помню. Другим вариантом было сохранение значения из «проблемного» API заранее в локальную переменную и уже использование этой переменной через замыкание в делегате.
Сам я везде в своих библиотеках всегда использую ConfigureAwait(false). Да, многословно местами, но это небольшая цена.
Зачем же вы так дезинформируете общественность объяснением первого примера? Сами же даёте ссылку на объяснения Эрика Липперта, где он последовательно объясняет, что никакого боксинга нет. А в статье говорите "потому что боксинг". А имеет место быть "embedded statement", когда значение структуры копируется/захватывается блоком using и манипуляции над копией не видны снаружи этого юзинга. Это огромная разница с боксингом.
Сам постоянно использую disposable struct (не mutable, а именно disposable), потому что это удобное средство простого профилирования участков кода аля
using (new Perf("Считаем интеграл методом №7"))
{
// some code
}
....
public readonly struct Perf
{
private readonly string _text;
private readonly long _startTime;
// etc
public Perf(string text)
{
_text = text;
_startTime = ... // засечь текущий момент времени и сохранить в поле
}
public void Dispose()
{
// засечь текущий момент времени, вычислить дельту, сбросить дельту в лог вместе с текстовкой _text (консоль/etc.)
}
}
И эта конструкция помогает естественным образом видеть тот кусок кода, для которого производится замер — визуально все в блок using завернуто красиво. При этом она не несет никаких накладных расходов на выделение памяти в куче.
Даже пришлось перепроверять это после прочтения, напугали. Но все хорошо — 0 bytes allocated )).
Да вроде не должно. Ведь это деконструктор, а после деконструкции x и y уже никак не связаны с объектом o — это просто переменные, в которые скопировалось внутреннее представление o.
and their contents are disposed at the end of the current statement block
То есть теперь будет проще ненароком увеличить время жизни disposable-ресурса? Текущий блочный стиль использования using делает очевидным место уничтожения ресурса — закрывающаяся фигурная скобка не даст соврать. С using declarations же, как я понимаю, добавление дополнительных строк кода в конец текущего блока будет зазря откладывать вызов Dispose, несмотря на то, что этим строкам ресурс может уже и не требуется.
Легко представить ситуацию, когда нужно в уже написанный метод спустя некоторое время добавить какое-нибудь логирование. Разработчик (не обязательно автор) открывает код, пробегает его глазами, не замечает using declaration где-то посередине (ибо он никак не выделяется теперь отступом от нижележащего кода) и с радостью вписывает последней строкой отправку логов. И теперь вызов Dispose пойдет после того, как лог запишется. В зависимости от внутренней гибкости/сложности/продвинутости системы конфигурации логов вызов может отрабатывать как мгновенно, так и с существенной задержкой, если под капотом разворачивается в синхронную запись на диск/БД/внешнюю службу. А у нас под using стояло открытое соединение с БД… В итоге можем получить плавующую непонятную проблему, когда на dev-окружении все будет летать (потому что логи там толком и не настроены), а на prod внезапно все колом встанет из-за того, что пул соединений исчерпается, ибо время удержания соединения открытым станет зависеть от скорости работы совершенно не относящегося к соединению с БД кода.
Нужно отметить, что в случае блочного using можно запросто достичь такого же эффекта, внеся код внутрьusing-блока, а не после него. Но сам дизайн работы с using-блоком предполагает сужение его настолько, насколько это возможно. Выделили ресурс, выполнили все реально необходимые с этим ресурсом действия и тут же его уничтожили. В коде четко видно место рождения ресурса и место его смерти. Теперь же место смерти неявное.
using statements always cause a level of nesting, which can be highly annoying and hurt readability
Nesting убрали, да. Улучшилась ли та самая readability? Очень сомнительно. Скорее появилась еще одна возможность накосячить.
Он один на все команды или есть командные тестовые контуры? В первом случае когда одна из команд тестирует свой код, то все остальные волей-неволей тоже его тестируют, нарываясь на непонятные чужие баги?
Какое отношение имеют к основному тексту сноски State transition и Decision table в заключении?
В это слабо верится, исходя из опыта работы в банковской сфере.
рекомендуем
На самом деле не такой уж он глобальный, а как раз весьма локальный, потому что включает/отключает эту фичу на конкретной схеме (тип Schema). Приложение может хостить сразу несколько схем, выставляя их наружу по разным урлам вроде ~/cats/graphql , ~/dogs/graphql . И вот по сути для каждой такой связки url+schema можно настраивать поведение. Короче говоря, флаг этот не статический, а экземплярный и живёт в каждой схеме.
"в" потеряно
Эвона как. Читал в новостях, но в аккаунт до сих пор зайти не могу.
Фугасные лямбды и нелетальные замыкания на подходе.
Вообще странно, новый аккаунт работает (пока работает, со вчерашнего дня). Я специально не заполнял ничего в профиле. По идее если сейчас за что-то там можно зацепиться, то это либо IP, либо адрес почтового сервера, который при регистрации указывается. Почта на яндексе, ru домен.
Да, о "действовать радикально" странная какая-то логика. Забанили на гитхабе - идешь к Кремлю метать зажигательные смеси что ли? Логика железобетонная.
Меня затронула эта зараза. Сегодня. Я на хабре вообще крайне редко, но вот в поисках информации набрел на статью и решил поделиться опытом. На гитхабе с 2016 года, поддерживаю десяток проектов, а мониторю несколько десятков. На постоянной основе поддерживаю
https://github.com/graphql-dotnet/graphql-dotnet
https://github.com/graphql-dotnet/server
https://github.com/graphql-dotnet/parser
https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks
https://github.com/EasyNetQ/EasyNetQ
и тд и тп.
Ессно, что убиваю на это дело прорву своего личного времени, сил и здоровья.
Первой реакцией было удивление и смех. Эдакое "нуемана, ну что же в творите, а"! Рабочий процесс выбили из под ног. Скоро релиз выпускать новой мажорной версии GraphQL движка и обвязки вокруг него, куча планов туда-сюда, а тут такое. И кто от этого потеряет? Смешно же, ну. У реп (Nuget пакетов, построенных из неё) миллионы скачиваний по всему миру. Пользуются сотни если не тысячи разработчиков. И теперь поддержка сего хозяйства местами будет буксовать, а местами встанет колом, доступы там получать надо некоторые, настройки делать. Белиберда.
Тикет им завел в поддержку. Там тоже посмеялся. Чтобы сделать тикет, нужно иметь аккаунт гитхаба. Завел другой аккаунт вот, почту под него завел. Залогинился в гитхаб (ура!) и сделал тикет. Надежды правда мало, что выйдет что-нибудь путное. И не известно, не заблокируют ли новый аккаунт.
Кстати говоря, интересно, на основании чего блокируют. История входов, где IP-адреса? Что-нибудь в профиле типа страны? Принадлежность к определенным конторам по указанным ссылкам в том же профиле? Вопросы, вопросы... Но суть одна - напакостили.
Но ничего, тут вопрос философский. Всегда надо давать возможность людям выстрелить себе в ногу, чтобы дать им понять, что из этого выходит. Отрицательный опыт - это тоже опыт.
Ну да. Сам же автор пишет, что
И после этого для блокировок использует тот же вечный кеш. Нужно тогда уж задавать eviction delegate каждый раз и в нем чистить за собой блокировку.
Да, можно и так сказать, в этом суть. Ведь
continueOnCapturedContext
— эта та же самая привязка делегата к контексту, только окольным путем через вызов изнутри библиотеки. Ну и с возможными побочными эффектами для других методов, вызываемых внутри.В самых простых случаях вы верно описали ситуацию. Добавлю от себя о вопросе необходимости задания
continueOnCapturedContext
. Реальность такова, что мы не используем библиотеки "атомарно". Как правило, выстроен целые стеки библиотек, эдакий слоеный пирог из функциональных слоев, где зачастую делегаты/события и прочие прелести передаются вверх и вниз по стеку вызовов. В таких ситуациях довольно сложно и накладно отслеживать, что кому нужно по контекстам синхронизации. Сейчас не нужно, в следующей версии библиотеки нужно. Невозможно, да и не стоит пытаться обременять вызывающие слои необходимостью заданияcontinueOnCapturedContext
. Да, в некоторых редкий ситуациях, особенно с легаси-кодом, вариант сcontinueOnCapturedContext
может быть меньшим злом.Сам я везде в своих библиотеках всегда использую ConfigureAwait(false). Да, многословно местами, но это небольшая цена.
UPDATE: lair говорит выше именно об этом.
Зачем же вы так дезинформируете общественность объяснением первого примера? Сами же даёте ссылку на объяснения Эрика Липперта, где он последовательно объясняет, что никакого боксинга нет. А в статье говорите "потому что боксинг". А имеет место быть "embedded statement", когда значение структуры копируется/захватывается блоком using и манипуляции над копией не видны снаружи этого юзинга. Это огромная разница с боксингом.
Сам постоянно использую disposable struct (не mutable, а именно disposable), потому что это удобное средство простого профилирования участков кода аля
И эта конструкция помогает естественным образом видеть тот кусок кода, для которого производится замер — визуально все в блок using завернуто красиво. При этом она не несет никаких накладных расходов на выделение памяти в куче.
Даже пришлось перепроверять это после прочтения, напугали. Но все хорошо — 0 bytes allocated )).
Да вроде не должно. Ведь это деконструктор, а после деконструкции
x
иy
уже никак не связаны с объектомo
— это просто переменные, в которые скопировалось внутреннее представлениеo
.То есть теперь будет проще ненароком увеличить время жизни disposable-ресурса? Текущий блочный стиль использования using делает очевидным место уничтожения ресурса — закрывающаяся фигурная скобка не даст соврать. С using declarations же, как я понимаю, добавление дополнительных строк кода в конец текущего блока будет зазря откладывать вызов
Dispose
, несмотря на то, что этим строкам ресурс может уже и не требуется.Легко представить ситуацию, когда нужно в уже написанный метод спустя некоторое время добавить какое-нибудь логирование. Разработчик (не обязательно автор) открывает код, пробегает его глазами, не замечает using declaration где-то посередине (ибо он никак не выделяется теперь отступом от нижележащего кода) и с радостью вписывает последней строкой отправку логов. И теперь вызов
Dispose
пойдет после того, как лог запишется. В зависимости от внутренней гибкости/сложности/продвинутости системы конфигурации логов вызов может отрабатывать как мгновенно, так и с существенной задержкой, если под капотом разворачивается в синхронную запись на диск/БД/внешнюю службу. А у нас подusing
стояло открытое соединение с БД… В итоге можем получить плавующую непонятную проблему, когда на dev-окружении все будет летать (потому что логи там толком и не настроены), а на prod внезапно все колом встанет из-за того, что пул соединений исчерпается, ибо время удержания соединения открытым станет зависеть от скорости работы совершенно не относящегося к соединению с БД кода.Нужно отметить, что в случае блочного
using
можно запросто достичь такого же эффекта, внеся код внутрьusing
-блока, а не после него. Но сам дизайн работы сusing
-блоком предполагает сужение его настолько, насколько это возможно. Выделили ресурс, выполнили все реально необходимые с этим ресурсом действия и тут же его уничтожили. В коде четко видно место рождения ресурса и место его смерти. Теперь же место смерти неявное.Nesting убрали, да. Улучшилась ли та самая
readability
? Очень сомнительно. Скорее появилась еще одна возможность накосячить.