MCP
Показаны сообщения с ярлыком индусы. Показать все сообщения
Показаны сообщения с ярлыком индусы. Показать все сообщения

вторник, 9 апреля 2019 г.

Странная реализация HttpClient в .NET Core

Представьте что у вас есть приложение. Не очень маленькое, но и не гигантское, работает помаленьку развивается, и тут вы совершенно случайно замечаете в мониторинге, что один из сервисов жрёт 25% CPU. Хм... вроде многовато, но мало ли что. Может боты набежали на сайт и смотрят все странички, или пользователи ходят. Да и 25% немного, запас огромный (400% максимум). Но на всякий случай сервис перепускается и загрузка падает до 1%. Вы думаете — какой-то глюк, но через некоторое время загрузка процессора растёт опять.

Вот с подобной ситуацией я столкнулся несколько недель назад. Есть какая-то утечка CPU (не памяти, а именно процессора), при этом ни истерики в логах ни каких-то явных знаков, указывающих на проблему. Приложение, хоть и не очень большое, но делает кучу разных вещей, отправляет письма, общается через собственную API-платформу, активно кеширует данные, связывается с другими частями и внешними сервисами, генерирует документы, в общем точек для анализа очень много. А утечка небольшая, несколько процентов в день, да и эти несколько процентов в моменте могут быть настоящей нагрузкой от живых пользователей. Т.е. даже не ясно как поступать с профилированием. Да и на деве это не повторяется.

Когда я в очередной раз сдался, я не выдержал, и подцепился дебаггером к боевому серверу напрямую. И... ничего не понял, всё выглядит нормально. Отцепился — загрузка 0%. Тут у меня уже задёргался глаз. Через некоторое время повторил — да, подключение дебаггера явно лечит проблему, как и перезапуск приложения. Но это ведь не выход и не решение. А вдруг это какая-то проблема у нас, и если в этом приложении данную проблему можно замаскировать, то она может выстрелить где-то ещё. Так что пришлось разбираться дальше.

Неожиданно удалось нагуглить данный тред на GitHub'е. Проблема у Microsoft'овской библиотеки и связана она с HttpClient. Утверждалось, что нельзя его создавать на каждый HTTP запрос, а надо использовать статичный. Правда в документации есть пример использования:

В котором его заворачивают в using. Я попробовал покопать в данном направлении и выяснил первую забавную вещь: использование статичного HttpClient в .NET Core быстрее раз в 5, чем создавать его на каждый запрос. Но тут нюансы с самим временем запроса, но смысл в том, что уже есть причина использовать статичную версию. При этом под "большой" .NET разницы нет никакой.

В общем, выложил новую версию приложения, но проблема осталась. (может я не туда копаю?). Попробовал переключиться с .NET Core 2.1 на 2.0 — проблема ушла. Т.е. проблема есть только под core, под Linux и версия должна быть больше чем 2.0 (более свежие не проверял). Читаем документацию и видим, как разработчики Microsoft, светясь от гордости, рекламируют новую реализацию Http Client Factory, через которую и идут все запросы (не может Microsoft просто написать библиотеку, делающие HTTP запросы, внутри обязана быть магия!). В общем теперь всё managed, в 10 раз лучше и в 50 раз быстрее. Ага, и сделано как раз в 2.1

Прикидываю, где ещё скрылись HttpClient'ы и нахожу библиотечку для отправки Push-уведомлений, которая внутри себя создаёт данный класс. Собственно, поэтому в первый раз и не было найдено это использование. Переделываю использование данной библиотеки и проблема исчезает! Всё работает замечательно.

Тут я начинаю громко материться, но нахожу в документации небольшую приписку:
Т.е. они знают о данной проблеме! Но явно про это написать было стыдно, так что засунули всё в сноску, зато не будет никаких претензий от разработчиков. Сноска есть? Есть! Значит читайте внимательнее.

Получается совершенно странная ситуация: Disposable-класс, который надо использовать синглтоном. При том, что все предыдущие реинкарнации подобных классов были честными Disposable-объектами. Но тут решили сделать по-другому. Зачем? Я пока не понял. Но свинью подложили знатную. Представьте, у вас есть базовая библиотека, написанная под большой .NET, вы её мигрируете на Core, пользуетесь под Windows, всё нормально, а потом, спустя длительное время замечаете, что приложение жрёт много процессора. Вам нужно будет пройти квест, подобный моему, чтобы найти проблему, переписать библиотеку и весь остальной код, обновить всё что нужно и всё из-за странного архитектурного решения разработчиков из Microsoft.

воскресенье, 10 февраля 2019 г.

Деградация Windows Server

Есть у меня простенький компьютер. Был куплен в порыве шопоголизма на распродаже. Я так и не придумал, чем занять данный компьютер, поэтому накатил на него Windows Server 2016 (По факту LTSB сборка 10-ой винды 1607, которая Anniversary Update, но с серверными фичами). Компьютер после запуска (и ожидания 8 минут, пока винда разберётся со своими внутренними делами) выглядел так:

Если не вдаваться в подробности, то запущено 54 процесса, 848 потоков и занято 0.9Гб оперативки. Вполне допустимая ситуация для пустого сервера, хотя всегда хочется меньше.

Но я решил потестировать недавно вышедший Windows Server 2019, эта та же Windows 10, только уже злополучная 1809, October 2018 Update. Я просто обновил сервер, подождал джентльменские 8 минут и результат на экране:

Процессов уже стало 110 (ровно в два раза больше!), количество потоков увеличилось всего на 300 штук, что уже лучше, хендлов стало больше почти в 2 раза и сожрано стало на 400МБ оперативной памяти больше.

Ещё раз, для понимания бреда. За 2 года разработки операционная система на свои личные нужды стала использовать гораздо больше ресурсов. Может от этого она стала быстрее или лучше работать? Как-то незаметно. Вместо оптимизации системы в итоге получаешь просто ещё больше внутреннего потребления. Зачем? А просто так, потому что программисты Microsoft могут тратить ресурсы как захотят. Железо же становится быстрее, памяти больше, никто и не заметит. И вот это бесит неимоверно.

UPD: Оказывается, это сознательное решение Microsoft, они в 1703 разгруппировали сервисы, если в системе больше чем 3.5ГБ памяти. Объяснили как всегда надёжностью и безопасностью. Но памяти это, конечно же, жрёт больше, о чём не скрывают. А то, что "стабильность" теперь зависит от количества оперативной памяти — выглядит это очень странно.

UPD2: Поиск решения проблемы привёл на следующую ссылку, надо в реестре по пути:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control отредактировать (создать?) ключ SvcHostSplitThresholdInKB, изменив там количество памяти для разделения процессов. Итог изменения ключа следующий:

Процессов и памяти резко уменьшилось. До старых значений ещё не доходит, но всё-таки результат стал получше. 

понедельник, 27 ноября 2017 г.

Ненавистный .NET

Последнее время совсем не пишу в блог, как-то нет подходящих тем, могу только сообщить, что такой ненависти к Microsoft я давно не испытывал. Попытка поработать с .NET Core 2.0 сразу же привела к идиотским ошибкам, типа 2 entry point у приложения. При этом второй генерируется самостоятельно (!), другими словами, у Microsoft новые отличнейшие идеи, как всё должно работать по их мнению, вместо того, чтобы просто сделать рабочий продукт.

Если кончится мат и появятся слова, постараюсь написать что-то более членораздельное. Но, блин, у Microsoft был отличнейший .NET, приложения на котором просто работали... Теперь не так, они могут падать по совершенно различным причинам, а Dll Hell уже перешёл все границы. Ну, как, как можно так портить жизнь разработчикам за их же деньги...

понедельник, 2 октября 2017 г.

Версионирование .NET Core

Когда-то писал про .NET Core и обещал написать больше, но было лениво, так что руки не дошли.

Сейчас просто для понимания бреда, который творится с версионированием краткое описание разных версий. Это может быть полезно, т.к. вышел .NET Core 2.0 и .NET Standard 2.0, и версии слились в экстазе. Но на самом деле они разные, и скоро разъедутся и будут опять портить всем жизнь. Итак, временно забудем про существование 2.0, и вспомним, что есть:


  • Вы собрались писать под .NET Core, соответственно выбираете, какую версию хотите, вы можете выбрать версию 1.0 (на момент написания 1.0.7) или 1.1 (на момент написания 1.1.4), при этом, особой разницы в этом нет. 
  • На самом деле, вы можете выбрать рантайм или сдк Логично, что для разработки нужен SDK, для версии рантайма 1.0.7, сдк имеет версию 1.1.4 (т.е. рантайм разрабатывается и старый и новый одновременно, сдк только новый)
  • После этого, вы можете решить, что использовать, .NET Standard или .NET Core. Для библиотек лучше использовать Standard, у него версии: 1.0,1.1,1.2,1.3,1.4,1.5,1.6, для запускаемых файлов лучше Core, у него версии 1.0 и 1.1
  • Впрочем, вы можете писать библиотеки на Core, а экзешники на Standard, в этом не очень много смысла, но в целом он есть
  • Версии Standard для удобства используют стандартную библиотеку NETStandard.Library, она бывает версий 1.6.0 и 1.6.1
  • В этой библиотеке есть стандартные библиотеки, которые любят называться как большие и иметь версию 4.3.0 (большие имеют версию 4.0.0). Впрочем, иногда бывают и 4.2.0 и 4.1.0, и всякие разные
Т.е. приложение мод .NET Core 1.0 может запускаться в рантайме 1.1.4, иметь зависимость на библиотеку .NET Standard 1.3, которая использует библиотеку NETStandard.Library 1.6.1 и это всё будет замечательно работать! Главное надо понять, что это просто разные версии разных библиотек. 

Сейчас вышел .NET Standard 2.0, и всё стало совсем просто: приложение под .NET Core 2.0 запускается в рантайме 2.0, имеет зависимость на библиотеку .NET Standard 2.0, которая использует библиотеку NETStandard.Library 2.0.0. К сожалению, скоро все эти версии опять разъедутся в разные стороны, и опять будет путаница. Но. надеюсь, вы теперь будете во все оружии.

PS: Сейчас слушаю про version hell в .NET Core 2.0, и становится страшно, там добавили совместимости из-за которой много всего развалилось, несмотря на обещанную совместимость.


среда, 8 марта 2017 г.

Visual Studio 2017 и очередная упоротость от Microsoft

Данный пост навеян статьёй о выходе VS2017, в которой есть такая шикарнейшая фраза:

We’re now encouraging Visual Studio 2015 users to migrate to MSBuild and csproj from project.json. As I stated above, we will not be supporting any of the new .NET Core tools in Visual Studio 2015. We also won’t be updating the Visual Studio 2015 project.json-based tools.
И вот эта фраза меня убило, хотя новости ходили давно, но тут они всё-таки сделали всё "в самом лучшем виде". И я не могу не высказаться по этому поводу.

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

В результате, часть времени в проекте уходит на миграцию на новую версию, часть на обучение разработчиков как сегодня правильно писать и часть на исправление незамеченных регрессов. В общем, это хорошо так перекликается с одним из моих ранних постов про велосипеды. Я, собственно, до сих пор предпочитаю использовать .NET 4.0: он работает начиная с XP и VS2010, он не мёртвый (апдейты выходят и для него, и свежие .NET улучшают его код, ибо в реальности одно и тоже), да и в новых не так уж и много полезных фич, чтобы переходить на него. Кроме того, никаких проблем с версионированием, которые поехали дальше: 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2 — без гугла различия и не вспомнишь.

Но тут решили делать всё по-новому и перешли на .NET4.6 и .NET Core, всё-таки у Core есть хорошие плюшки в виде нативной компиляции и гарантированной работы под Linux, да и разрабатывается она давно.

Про сам .NET Core писать не буду, ибо мелочь уже написана, на на ещё один пост не набирается, но вот что понравилось безоговорочно, это файлы project.json, которые очень похожи на package.json, но для Core. Собственно, наконец-то у Microsoft получился вменяемый формат проекта, который можно редактировать ручками не в плане хотфиксов, а прямо-таки изменять поведение проекта. Ну и работать с проектом не только в студии, но хоть в саблайме.

И тут приходит Microsoft и говорит, извините, факир был пьян, мы возвращаем всё назад. При этом новые фичи будут работать только в новой студии, а старые поддерживать мы больше не будем. Т.е. фактически кинули всех владельцев 2015-ой студии, которые работали с проектами на Core. При этом Microsoft всю жизнь тащила обратную совместимость, ибо так правильно и ынтырпрайзно.  Но, судя по всему, в команде .NET царит атмосфера вида: как хочется и как им удобнее. В результате, мало того, что ты летишь в самолёте, у которого по ходу дела меняют крылья на другие, ещё и забирают двигатели с фразой — они отстой, в новых всё лучше, покупайте наших слонов!

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

Эээх... как же хорошо было в .NET4.0...

четверг, 15 декабря 2016 г.

Краткий анализ .NET Core/Standard/Framework

Тут в очередной раз разбирался с тем, что в Microsoft нагородили с .NET, пока окончательно не понял, но в целом, чтобы не пересказывать основные статьи про всё это дело, просто сообщу, то что я понял:

  • Есть .NET Core, это специальный кроссплатформенный фреймворк
  • Есть .NET Framework, это классический .NET, работающий под винду
  • Есть .NET Standard, это набор API, который гарантированно будет работать в .NET Core и .NET Framework (ну и всяких ксамаринах)
  • Код, изначально написанный на .NET Framework, не будет работать под .NET Core
  • Если есть желание писать под .NET Standard, чтобы работало под большим .NET Framework, то лучше не делать так. Ибо работать будет, но плохо.
  • Потому что вся магия в том, что API похожее, но разное. 
  • Другими словами, версия под .NET Framework будет использовать очень похожий, но отдельный набор API. Если он весь скрыт внутри. то ничего страшного, никто не увидит. Если же вылезает наружу, могут быть неприятные последствия.
  • Ещё раз уточню, что если написано, что Standard 1.2=Framework 4.5.1, то это не значит, что код, написанный под 4.5.1 будет работать на уровне 1.2. Это просто значит, что если написать код, под 1.2, то его с помощью бубна можно заставить работать на 4.5.1. При этом набор API в 1.2 особо нигде не расписан, например, там нет криптографии. Странно, но вот так.
  • Судя по всему, самая популярная версия .NET Standard — 1.3, что в ней такого особого, пока не разобрался
Т.е. в целом ситуация складывается странная. Если хочется разрабатывать универсальные вещи, то лучше тупо не думать, а разрабатывать под .NET Core, забив на .NET Framework полностью. Потому что поставить .NET Core не сложно, а существущий код под .NET Framework всё равно придётся переделывать, так что, смысла во взрослом фреймворке на мой взгляд немного.

PS: Возможно, после дальнейшего знакомства со всем этим делом, моё мнение изменится, тогда обновлю пост. Но пока есть ощущение ужасной неразберихи и путаницы в API, чего стоит только набор версий фреймворка 4.5, 4.5.1, 4.6, 4.6.1, 4.6.2 — надо долго гуглить, чтобы найти отличия, но при этом для каждого из них, есть своя версия .NET Standard, но, поскольку, скоро будет .NET Standard 2.0, использовать .NET Standard 1.5 и 1.6, не рекомендуется из-за проблем с совместимостью. Ещё раз, стандартная версия фреймворка, сделанная для совместимости, будет несовместима сама с собой. А нам с этим жить...

среда, 6 апреля 2016 г.

Windows Update ошибка 800F0922

Собственно, данный пост на случай, если его нагуглят, ибо гугление ошибок с виндовым апдейтом — самое милое дело. Других сведений про источник проблемы обычно нет.
Итак, я долго возился с тем, что у меня не ставились некоторые обновления. Занимался уже делением пополам и установкой того, что ставится (ибо, если не ставится одно, откатываются все пакетом, ибо транзакционность). Но на днях решил разобраться, в чём же причина.
Собственно, т.к. не ставилась куча апдейтов, код конкретного не привожу, но ошибка была с кодом 800F0922, и выглядела примерно так

Гуглёж по коду выдал кучу безумных рекомендаций вида — удалить драйвер Cisco VPN или увеличить служебный раздел System Reserved. А также стандартные пляски с бубном вида sfc /scannow и сброса состояния Windows Update. Но первые причины явно были не мои, а вторые помогают только, когда действительно сломано всё. У меня же были проблемы только с частью апдейтов.

В общем, я пошёл копать в логи, которые у апдейтов находятся в C:\Windows\Logs\CBS\CBS.log на предмет, того, что же там не так. А не так там оказалась подобная строчка (хана дизайну блога, ну да ладно):

2016-04-05 10:03:35, Error                 CSI    00000001 (F) Logged @2016/4/5:07:03:35.059 : [ml:262{131},l:260{130}]"events installer: online=1, install=1, component=wow64_Microsoft-Windows-Win32k_31bf3856ad364e35_6.2.9200.17461_neutral_release__."
[gle=0x80004005]
2016-04-05 10:03:35, Error                 CSI    00000002 (F) Logged @2016/4/5:07:03:35.090 : [ml:240{120},l:238{119}]"EventAITrace:Provider Microsoft-Windows-Win32k is already installed with GUID {e7ef96be-969f-414f-97d7-3ddb7b558ccc}.

"
[gle=0x80004005]


2016-04-05 10:03:35, Error                 CSI    00000003 (F) Logged @2016/4/5:07:03:35.090 : [ml:168{84},l:166{83}]"WmiCmiPlugin manproc.cpp(683): InstrumentationManifestAssert failed. HR=0x80073aa2."
[gle=0x80004005]


2016-04-05 10:03:35, Error                 CSI    00000004 (F) Logged @2016/4/5:07:03:35.090 : [ml:166{83},l:164{82}]"WmiCmiPlugin eventloghandler.cpp(192): ProcessEventsInstall failed. HR=0x80073aa2."
[gle=0x80004005]


2016-04-05 10:03:35, Error                 CSI    00000005 (F) Logged @2016/4/5:07:03:35.090 : [ml:170{85},l:168{84}]"WmiCmiPlugin eventloghandler.cpp(212): EventLogHandlerInstall failed. HR=0x80073aa2."
[gle=0x80004005]


2016-04-05 10:03:35, Error                 CSI    00000006@2016/4/5:07:03:35.090 (F) CMIADAPTER: Inner Error Message from AI HRESULT = HRESULT_FROM_WIN32(15010)
 [
[22]"Configuration error.

"
]

аКлючевое в этом: EventAITrace:Provider Microsoft-Windows-Win32k is already installed with GUID {e7ef96be-969f-414f-97d7-3ddb7b558ccc}, т.е. в переводе на русский, уже есть источник журнала событий, а его опять пытаются сделать. Почему бы не успокоиться, я не знаю. Но решение тут банальное:

  • идём в реестр в ветку HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Publishers\{e7ef96be-969f-414f-97d7-3ddb7b558ccc}
  • Экспортируем её на всякий случай
  • Удаляем
  • Перегружаемся (это важно)
  • Пробуем установить апдейт заново
И чудо! всё заработало. Все апдейты стали снова ставиться без проблем.
Это, естественно, не единственный вариант источника проблемы, но, может быть в вашем случае он поможет.

суббота, 5 сентября 2015 г.

Microsoft EDGE

Смотрю я на данный браузер и поражаюсь, Microsoft в очередной раз сосредоточилась не пойми на чём, вместо того, чтобы сделать удобный браузер. Вся реклама основана на том, какой он быстрый, хотя в реальности ничего особо быстрого нет, обычный средненький по производительности браузер. При этом, в плане использования всё очень плохо, и видны торчащие ноги из IE.

Собственно по пунктам, банальные вещи, которые видны сразу:
  • Если обратиться к сайту на нестандартный порт, браузер не догадается что он предназначен для http и с упорством дебила пойдёт гуглить, что же ему подсунули. Ну детский сад же... UPD: это исправлено, претензия снимается
  • Восстановление сессий, вроде бы старая и must have фича, по-прежнему работает некорректно. А именно, постоянно восстанавливается куча пустых вкладок. Откуда, блин, он их берёт?
  • При запуске, если система тормозит, то при попытке ввести адрес, добрый браузер сотрёт его, и нарисует вместо него свою домашнюю страницу. Блин, я уже собираюсь уйти куда мне надо, не решай за меня!
Все эти пункты тянутся с IE и до сих пор не пофикшены, хотя в любом другом браузере — работают гораздо лучше. Неужели разработчика браузера запрещено смотреть на другие, не дай бог, сделают что-то удобное.

При этом в Edge оторвали всё хорошее из IE — акселераторы, фрагменты, плагины. Интерфейс теперь стал одним из самых габаритных среди других браузеров (а раньше хвалились, что они экономят место), окна браузера теперь все объединены в один значок, а не делятся на отдельные как в IE...

В общем, в очередной раз, Microsoft решила всё переделать, но начала переделку с копипейста и отрывания функционала. Буду с нетерпением ждать очередной реинкарнации браузера и рассказов о том, насколько теперь он быстрее.

воскресенье, 30 августа 2015 г.

Проблемы REST API или Яндекс тоже лажает

Вчера заметил лажу Яндекса в реализации REST API и решил немного высказаться про идеологов правильного использования REST.

Под данными идеологами я понимаю людей, которые месяцами выбирают HTTP-метод (PUT или PATCH? Сложный выбор!), вылизывают урлы (так, /user/add/group или /group/add/user, или POST /, а остальное данными?), при этом по факту никому их API никогда не нужно, а если и нужно то используется через врапперы и библиотеки.

Красивые урлы и семантика, конечно, важна, но проблема в том, что REST работает через HTTP со своими заморочками и ограничениями. Например, в GET нельзя закидывать body, и надо пытаться засунуть всё в URL, а если не влезает, то сделать POST, получить ID запроса, и сделать GET. Идиотизм. зато семантично.

Или моё любимое: по стандарту GET-ответы кешируются, если не сказано иное (хотя хрому наплевать на это). Звучит разумно, например, мы получаем текущую фазу луны, никаких параметров, она всегда одинаковая, хотя... стоп... Давайте что-нить попроще, например количество входящих сообщений пользователя... блин... Пол пользователя! Во! Главное, чтобы он к врачу не сходил. В общем, если умерить сарказм, то получается, что GET-запросы для API практически никогда не надо кешировать, ибо хоть они и получают данные, но те данные имеют тенденцию меняться в самый непредсказуемый момент.

Решений для убирания кешироания несколько:
  • С сервера посылать запрет кеширования. Работает, но несемантично
  • К каждому запросу подсовывать рандомную строку. Работает, но выглядит ужасно и по факту засираем кеш браузера
  • Переделать API так, чтобы в нём участвовала рандомная строка. Например, дать количество сообщений пользователя на определённую дату. Пофиг, что кроме текущей мы ничего не можем сделать, зато прикрутили параметр
  • Делать POST, а потом GET - очень глупо, медленно, неудобно, но семантично
В общем, вместо того, чтобы тупо сделать всё на POST'ах, мы активно боремся с инфраструктурой. И подобные проблемы периодически возникают то тут, то там. И борьба с ними идёт в основном ради красоты.

К чему всё это я — моё мнение, если вы не пишете могучее API для использования миллионами людей, то и не парьтесь, а если пишете — то сделайте SDK для него, и тоже не парьтесь. И все будут счастливы, кроме горстки перфекционистов.

Собственно, а что с Яндексом? Дело в том, что недавно они написали умную статью, о том как работать с HTTP, типа учитесь как правильно. Ок, поучился. Захожу на internet.yandex.ru и вижу картину следующего вида:
Естественно, со временем всё было в порядке. Просто я обновил данную страницу в браузере, а запрос о времени, сделанный по всем правилам Яндекса по урлу http://yandex.ru/internet/api/v0/datetime/ не имел никаких параметров кеширования. Что привело к тому, что браузер честно отдал ответ, который он запомнил 6 часов назад.
Как видите, Яндекс умеет делать красиво, рассказывать всем как правильно, только выкатывает в итоге нерабочий сервис.

UPD: Увидел ссылку, которая описывает архитектурные проблемы REST чуть в другом ключе, но пересекается с данным постом и я с ней в целом согласен. Также, могу сказать, что в одном из проектов я использовал JSON-pure API, и с ним не было никаких проблем. Данный код до сих пор бродит по разным проектам и не вызывает нареканий.

вторник, 2 июня 2015 г.

Чудесатые интернеты

Решил написать про бредовую ситуацию, с которой я сегодня столкнулся. Связана она была с настройкой виртуалки в Амстердаме у Infobox.

Итак, есть виртуалка, вроде бы всё работает, но при попытке достучаться по самбе, получаю ошибку. Фактически, блокируются 135, 139 и 445-ые порты. Я поплясал с бубном, помучал фаирвол, всё бестолку. В конце-концов, решил проверить доступ с внешней машины. Он был. В полном офигении, я начал копать проблему дальше, и выяснил следующие факты
  1. Любой порт кроме этих трёх работает корректно
  2. Эти три порта работают корректно из любой доступной мне сети (и интернет-утилит), кроме рабочей
  3. Из рабочей сети доступ на данные порты на другие внешние сервисы открыт и работает
  4. Никаких запретов на подобное во внутренней сети нет
Т.е., фактически получается, что или провайдер, или хостер рубят эти три порта, именно для нашей сети или для сети хостера. Совершенно безумная ситуация, которая по идее невозможна, а если возможна, то кто-то ведёт себя очень плохо.

Есть, конечно, другой вариант. Он заключатся в том, что я таки сошёл с ума, и мне всё это кажется. С учётом бредовости ситуации, этот вариант допустим.

Вот так, блин, и работаем.

UPD: Оказалось, что это посредник Инфобокса блокирует часть портов, почему-то считая именно эти "небезопасными". Причём, блокирует только с части сетей. Признались они только после длительной переписки с саппортом.

вторник, 26 мая 2015 г.

Управление виртуалками для обычных пользователей в Hyper-V 2012 R2

Microsoft иногда очень оригинально относится к безопасности. Перекроет все щели так, что прорваться могут только админы. А потом начинает ныть, что же все сидят под админами. Ну, может быть, потому что кто-то ленится подумать про права?

В своё время, Microsoft выпустила сервер виртуализации Hyper-V, весьма неплохой, хоть и со своими тараканами. И там можно было сделать замечательную вещь: выдать пользователю права на виртуалку, которая крутится на сервере. Т.е. он мог её включать, выключать, дёргать у неё сеть, но при этом, он постоянно к ней подключён, и в тоже время не видит соседей.

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

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

Зато, после всех этих мучений, можно было весьма гранулированно раздавать права через AzMan (я, кстати, первый раз его видел, хотя, судя по всему, существовал в системе давно, с XP. Но мы-то знаем, что Microsoft не ищет лёгких путей и всегда есть по крайней мере три несовместимых технологии).

К сожалению, в 2012 R2, эта магия больше не работает. Всё сломано. Мне понадобилось достаточно длительное время, чтобы понять это, т.к. народ умудряется писать статьи о том, что всё таки работает. Не работает. Проверено. С большим скрежетом, я всё-таки нашёл, что можно с этим сделать. А сделать можно только одно: давать пользователю подключаться, к виртуальной машине. Т.е. включить он её не может, но хотя бы может работать с ней. Для того, чтобы как-то добавить права, судя по всему нужна отдельная прослойка, которая со своими жирными правами будет всё делать, уже сам раздавая права. Данной прослойкой может быть System Center Virtual Machine Manager или что-то своё самописное (можно добавить имперсонацию и рулить юзерами, действия тупо выполнять через PowerShell). Но само подключение можно реализовать чуть проще, хотя и не очень очевидно.

Собственно, для возможности подключения пользователя (не админа) к определённой виртуалке надо сделать следующее):

  1. Выдать права на виртуалку через PowerShell
    Grant-VMConnectAccess -ComputerName host_name -VMName vm_name -UserName user_name
    Есть ещё команды Get-VMConnectAccess для просмотра прав и Revoke-VMConnectAccess для отбирания
  2. В PowerShell выяснить id-нужной нам виртуалки
    Get-VM -ComputerName host_name | select id,name
  3. Установить Remote Desktop Connection Manager (стандартный не катит)
  4. В нём сделать новую группу, в группу добавить сервер, на вкладке Server Settings поставить VM Console Connect, ввести нужный Id и сохранить всё это дело


После этого можно пользоваться прямым подключением к виртуалке (возможно придётся открыть ещё порт 2179).

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



четверг, 23 апреля 2015 г.

Ещё одна проблема HttpWebReqest

Я уже писал про грабли HttpWebRequest, но тут нашёл ещё одну забавную, и местами неприятную. Правда наполовину она относится к HttpWebResponse, но классы связаны метровым канатом, так что не принципиально.
Вкратце: работа с куками организована очень оригинально, и не очень логично.

Для удобства распишу по условным пунктам. Для начала диспозиция:
  • Сервер возвращает куки в Http-заголовке Set-Cookie
  • Если надо установить две куки, сервер передаёт два заголовка (не очень логично, но ок)
  • HttpWebResponse имеет пропертю Headers, и по имени заголовка можно получить значение
Тут начинаются проблемы, ибо куки две, а заголовок один. Как вы думаете что вернётся? Не буду томить, скажу, что вернётся в этом методе содержимое двух кук через запятую. Очень, блин удобно. Считаем, что куки у нас разломаны в этом виде.

Но! У Headers можно взять значения через .GetValues(), вернётся честный массив из двух элементов. И вроде бы всё хорошо, и пост можно жакончить, но тут приходит сервер, и выдаёт нам:

Set-Cookie: ABC=123; expires=Fri, 31 Dec 2010 23:59:59 GMT; path=/;


Вы заметили, что между пятницей и 31-ым числом есть запятая? HttpWebResponse тоже заметил, и вместо этой куки честно вернул нам две, обе разломанные. Всё, приехали.

Но обойти это надо, поэтому можно сделать следующие вещи:
  • Вручную распарсить значения кук, зная, что запятая, по стандарту, запрещённый символ. Т.е. встретится она может только в expires
  • Взять у HttpWebResponse пропертю Cookies, с уже обработанными куками
Вроде второй вариант самый правильный и логичный, за исключением случаев, когда вам хочется посмотреть на изначальные данные от сервера, а не обработанные странным кодом. Но чтобы он работал, надо обязательно, у HttpWebReqest установить пропертю CookieContainer, иначе вам вернётся пустой массив в респонзе.

request.CookieContainer = new CookieContainer()

Немного нелогично (нам ведь только ответные нужны), но в принципе допустимо. И всё из-за весьма странной реализации работы с заголовками.

На этом всё, буду ловить очередные грабли данного класса. 

воскресенье, 28 декабря 2014 г.

Новогоднее RDP

Скоро новый год, а значит выходные, т.е. к серверам лучше не прикасаться, а если прикасаться, то аккуратно. Естественно, Microsoft всех приучило, что самый простой и ненапряжный способ это сделать - RDP (нет, конечно, PowerShell рулит и бибикает, но назвать этот способ простым, как-то язык не поворачивается).

Итак, RDP живёт, проблем вроде бы нет, но... в один прекрасный момент вы обнаруживаете следующую картину, которые можете наблюдать продолжительное время без видимых результатов.


Другими словами, при попытке подключения — RDP тупит, а потом идёт отлуп с пространными объяснениями, что всё плохо.
Вы дома, сервер далеко, к нему не подойти и не пнуть ногами. Подключиться — не удаётся.
Практика показывает, что это частое явление при разрывах сети. Т.е. кроме разрыва соединения, ещё появляются такие шикарные эффекты. Причем страдают обычно 8-ые винды (т.е. Windows Server 2012 и 2012 R2)
Что в этом случае можно сделать?

Для начала, конечно же выполнить пункт номер 0 — иметь пути отхода и дырку в фаирволле. Причём делать это по-возможности всегда. Т.е. у вас всегда должно быть как минимум 2 пути подключения к серверу (например через рабочий компьютер и через другой сервер), и желательно на определённые IP иметь хороший список открытых портов для этих дружественных компов. Винда это вам не Linux, тут одним SSH не обойдёшься, особенно когда так тупит RDP!

Вариант первый, банальный и неинтересный:
shutdown /m \\server /r /t 1
Отправляем компьютер в ребут... очевидно и неинтересно. Надо идти другими путями. Другие пути заключаются в том, что надо бы перепустить службу Remote Desktop, которая зовётся TermService.

Тут 2 варианта:
sc \\server restart TermService (оцените синтаксис команды относительно предыдущей)

Или же, с помощью мышки: mmc.exe, добавить остнаску, службы, другой компьютер, перезапуск.

Но, тут как всегда нас ждёт сюрприз... в 90% случаях служба зависнет и не захочет останавливаться. Так что придётся добивать её ногами. Битьё усложняется тем, что она висит в процессе svchost.exe (благо обычно на нужном ничего полезного нет).

Так что
tasklist /s server /svc | findstr TermService (оценили синтаксис?)
taskkill /s server /pid 123456

Ну и запускаем службу. Вроде просто и очевидно, но как всегда лезут нюансы: если у нас плохо с логином и паролем (а мы дома, а не в домене), то получим отказ в доступе. Некоторые команды имеют возможность указать логин с паролем, некоторые используют существующее соединение (net use \\server\c$ - получим замечательное подключение и для управления), некоторые просто отказываются работать.

Можно применить PowerShell, создать сессию на сервер и там всё сделать, но ведь его надо настроить... добавить доверие... в общем если вы не занимаетесь этим специально, работать не будет.

Так что, если всё плохо и ничего не работает, то придётся ползти в сторону Sysinternals, а именно PsTools, и через psexec уже всё делать. Что удивительно, работает это гораздо надёжнее, чем встроенные средства системы. Даже если не разбираться, можно написать


psexec \\server tasklist /svc

И получить тот же результат (да, мне лень изучать другие команды из этого набора ).

Собственно, зачем я это написал? Вроде очевидные вещи. Да в общем-то с двумя простыми целями: в очередной раз поныть на винду, и показать, что если что-то не работает, можно всё-таки обойтись без перезагрузки.

UPD: Спустя время, надо бы добавить ещё пару команд, которые помогут решить подобную проблему. Ибо у Microsoft всё устроено очень сложно, половина команд может работать, а другая половина не работать с дурацкими сообщениями вида (не шутка):
Couldn't access server:

The operation completed successfully.

Соответственно, tasklist /svc в нашём случае можно заменить на
sc queryex TermService

А вот с taskkill посложнее. Может прокатить скрипт на PowerShell
Invoke-Command -ComputerName server -ScriptBlock {Stop-Process -Id 123456 -Force} -Credential DOMAIN\user

воскресенье, 19 октября 2014 г.

Android. Часовые пояса. 2014 год.

UPD: Дальнейший анализ показал, что на некоторых телефонах возможно чуть более простое обновление файлов, не перепрошивкой, а просто любым системным приложением. К сожалению, обновляют таким образом очень мало производителей (Samsung, и, местами, HTC), что оставляет пост в силе.

Заканчивается 2014-ый год, в России опять переводят время, все телефоны опять начнут страдать фигнёй и путаться в показаниях.Меня удивляет, что несмотря на многочисленные пинки и тычки (а часовые пояса постоянно кто-то меняет, недавно, например, хорошо отличились Чили и Египет), в Андроиде не только не хотят подумать над автоматическом обновлением часовых поясов, даже не хотят нормально решить проблему их установки в новых прошивках. Например, у меня сейчас телефон с прошивкой недельной давности, в котором стоят зоны от 2013 года!

Немного технической информации для понимания механизма: практически во всём мире (кроме Microsoft, конечно же), информация о часовых поясов берётся из полуофициальной базы TZ Database. Я говорю полуофициальной, потому что, несмотря на контролирование этого файла IANA, по факту изменения в него вносятся обычными людьми. Т.е. я узнал, что в России будут новые часовые пояса, написал письмо и файл обновили. Никакого официоза (конечно, я надеюсь, что эту информацию хотя бы проверяют по новостям).

Эта база имеет формат ГодБуква, где год — это год обновления базы, а буква — порядковый номер обновления. На данный момент это 2014h, следующая будет 2014i или 2015a, в зависимости от того, когда выйдет.

База представляет собой набор текстовых файлов определённого формата, которые под *nix компилируются в специальные бинарные файлы с правилами. Текущая зона вешается симлинком на один из этих файлов. Например, на Europe/Moscow.
В других системах, эта база может иметь другой вид. Например, на андроиде до версии 4.3, это было 3 файла, но с версии 4.3 — стал уже один. Значит зачем-то программисты подбирались к этому коду, но совершенно не подумали о том, что он может устареть.

И вот эта глупейшая ситуация, меня убивает. За столько лет существования Android, совершенно не думать о том, что данные могут меняться. Уму непостижимо. Я понимаю, американцы, которым плевать на весь окружающий мир, но ведь разработчики есть из разных стран, тем не менее, ничего сделано не было.

Конечно, если у вас есть рутовые права на телефоне, вы можете воспользоваться программой TimeZone Fixer, которая делает ровно одну вещь: копирует 3 файла в нужную папку. Эти 3 файла решают все проблемы. Но к сожалению, программе нужен рут, что не у многих есть. Вот так приходится работать за ленивых гугловских программистов, которым гораздо веселее в 7-й раз перерисовать иконки, чем сделать что-то полезное для людей. 

суббота, 24 мая 2014 г.

Деградация размера MFT от времени

Небольшая заметка посвящена тому, что недавно я обнаружил тот факт, что MFT в Windows не умеет уменьшаться.

MFT — это базовый служебный файл файловой системы NTFS, в котором хранится информация обо всех остальных файлах. Всё это весьма неплохо работает, но есть различные грабли. Сегодня расскажу про один косяк, связанный с тем, что MFT может только расти.

Представьте ситуацию, вы создали на диске миллион файлов (что не так уж и сложно), а потом их все удалили. В результате, казалось бы, место должно вернуться к исходному значению, но оно не вернётся. Потому что в MFT остались записи об этих удалённых файлах, которые никто не собирается чистить. С учётом того, что размер записи обычно порядка 1Кб, вы получили 1Гб мусора, который ни к чему хорошему не приводит. Вроде немного, но всё равно неприятно.

Хорошая новость состоит в том, что если вы опять закините этот миллион файлов, MFT переиспользует своё место и расти не будет. А если не планируете, и ваш перфекционизм мешает спать, то единственный вариант, который я вижу — бекап существующих файлов, форматирование диск и восстановление.

Если вы найдёте способ лучше, буду премного благодарен.

суббота, 29 марта 2014 г.

Паранойя в андроиде, или как задолбать пользователей

Я неоднократно говорил, что если перекрутить безопасность в приложении, то это приведёт к тому, что пользователи будут отключать её, лишь бы не бесила. Или бездумно кликать на "Разрешить", потому что это окно лезет всегда.
Примеры: UAC в Vista, который лез на каждый чих (в семёрке стал реже появляться), или sudo в SUSE, которое лезет на каждое действие. Пришлось рутовый пароль поставить в 1, чтобы хоть как-то можно было жить.

Но недавно я столкнулся с другой концепцией безопасности. В Андроиде. Её политика заключается в режиме: раз ты используешь это, ты идиот, и мы будем тебе говорить про это. И эта концепция выбесила до белого каления.

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

Казалось бы, что страшного в установке дополнительного сертификата? Ну есть проблемы, что с помощью него могут подменять сайты, но ведь в системе и так установлена сотня сертификатов, которые никто не проверяет. И вполне может быть дырка для гугла, для производителя телефона, просто любимый сертификат АНБ. И никто по этому поводу не нервничает. Что сделали в гугле? Сразу после установки появляется неотключаемая нотификация, о том что установлен сертификат. Ещё раз. Нотификация. Неотключаемая. Т.е. вам всю жизнь надо жить с иконкой, где написано что ты идиот, даже если это не так.
Решается данная проблема с помощью рута и переноса сертификата в системное хранилище. Глупо, зато хотя бы можно решить. Через одно место, но проблему хотя бы можно решить.

Но появилась другая проблема. Мне нужен клиентский сертификат. И он работает. И всё хорошо. Но в гугле решили, что я должен себя обезопасить, и обязан включить блокировку планшета с паролем, пин-кодом или графическим кодом. У кого такая блокировка уже включена, те даже не заметят проблему. Но я тестирую на планшете, основная цель которого — смотреть фильмы, читать книжки и кидаться птицами в свиней. И ради одного сертификата, я должен включать блокировку? Да нафига? Была бы идея, если бы к этой блокировке были бы привязаны другие данные. Но если посмотреть: браузеры сохраняют пароли для сайтов, система сохраняет пароли для WiFi и Bluetooth, приложения сохраняют пароли для почты, аккаунтов синхронизации, и доступа к внешним сайтам. Это нормально. Я могу взяв чужое устройство читать чужие письма, смотреть чатики, ходить по сайтам с паролями. Никаких проблем. Но если мне вдруг понадобился клиентский сертификат, я сразу же должен всё запаролить. На мой взгляд полный бред.
Решения этой проблемы я не нашёл. Только косвенное, с установкой сертификата, тестированием и удалением. По-моему бред. Зато можно жить.

Теперь я как программист считаю разработчиков Андроида — мудаками. А как обычный пользователь — всех программистов мудаками, которые мешают мне разговаривать с котиком и кататься на машинках. Не надо так.

воскресенье, 29 декабря 2013 г.

Про Internet Explorer

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

Итак, во всех рекламных статьях про новый браузер Microsoft упорно напирает на скорость и поддержку стандартов. И тут я действительно вижу улучшения. Всё достаточно шустро уже с 9-ой версии (правда, 8-ая была тем ещё тормозным ужасом), и уже можно пользоваться для обычной жизни. Но есть одно но. Имя ему интерфейс.

Судя по всему, интерфейс браузера пишет отдельная команда, и делает это из рук вон плохо. Я уже привык к мелочам, что ошибки от браузера не добьёшся. Только дурацкая страница, что ты дурак и сделал что-то не то. Недавний пример: браузер захотел идти по TLS1.2, а сервер (IIS) отдал ему TLS1.1. В результате — дурацкий текст ошибки. Хорошо, что был хром, который открыл страницу и всё объяснил.

Но у интерфейса есть более серьёзные проблемы. Во-первых, IE ещё ни разу не восстановил корректно вкладки. Постоянно меняется порядок и появляются фантомные дефолтные страницы. Эта катавасия тянется с тех пор, как в нём появились вкладки. Подобных проблем нет ни у одного другого браузера.
Во-вторых, модальные окна и невозможность остановить скрипты, если что-то пошло не так (например, зацикленный alert можно убить или с помощью ловкости или убийством из таск менеджера всех процессов IE — а потому что не найти нужный). Но модальность, на то и модальность, чтобы доводить до белого каления. Представьте, у вас есть сайт, который использует NTLM-авторизацию (или клиентские сертификаты). При его открытии вылезает окно с требованием ввести логин и пароль. Если в это время перейти на другую вкладку, и сделать это в очень правильный момент, можно получить ситуацию, когда браузер упорно не реагирует на команды, ибо я должен сделать что-то в модальном окне, которое спрятано в другой вкладке. Всё, приехали. Task Manager, killall iexplore.exe

В-третьих, в IE какая-то очень сложная работа с процессами. Смерть в одной вкладке обычно приводит к рандомной перегрузке ещё нескольких соседних. Зависимости я так и не понял. Ну и повалить весь браузер не смотря на отдельные процессы не очень сложно. Я умудрялся это сделать обычным JavaScript'ом. (К сожалению руки не дошли вычистить из данного скрипта всё лишнее и отдать на растерзание общественности). 

В-чётвёртых, в IE достаточно неплохие инструменты разработки, но оооочень тормозные. DOM-дерево строится иногда секунд по 10 и требует постоянного ручного рефреша, а другие браузеры не напрягаясь рисуют его динамически сразу.

Есть и другие мелочи, но это уже будет мелкими придирками, главное что качество реализации интерфейса в IE хромает на оба костыля. Поэтому невозможно данному браузеру доверить роль основного, слишком опасно.

Вчера, последней каплей, заставившей меня написать истеричный вопль была рядовая ситуация: я открыл сайт, открыл инструменты разработчика, включил отладку Javascript, тут браузер упал весь, а после поднятия не осталось ни одной из 15-ти вкладок. Сессия потерялась вовсе, как будто бы её и не было. В результате я, посреди отладки, начал вываливаться из контекста и стал заниматься попытками восстановления нужных вкладок, чтобы потом продолжить работу. Ну вот как с таким можно жить?

воскресенье, 25 августа 2013 г.

Деплой различных по стабильности версий продукта

Сейчас стало довольно модным использовать следующую модель версий продуктов (Google первый начал, остальные подхватили):
  • Developer — фактически транк, в котором тестируются новые фичи, стабильность не гарантируется и даже декларируется что её может не быть
  • Beta — фичи заморожены, идёт багфиксинг. Стабильность повышается со временем
  • Stable — полностью стабильная версия, обновления выходят только в случае обнаружения серьёзных проблем.
Кроме этого, обычно версионирование идёт по +1, т.е. Stable имеет версию n, Beta — n+1, Developer — n+2.
Когда Beta полностью оттестирована, она переходит в Stable и все версии щелкаются на единичку.

В общем, это всё всем понятно и известно. Но хочу поговорить о таком моменте: в любой момент времени свежесть версий должна идти в этом же порядке. Т.е. даже если сейчас идёт подготовка к релизу стабильной версии, в Beta и Developer должно быть по крайней мере тоже самое. Очевидно? Вроде бы да. Но я сейчас вижу перед глазами свежую Оперу, у которой на момент написания поста самая свежая версия это Beta (Next), а Developer, гораздо древнее. Т.е. явное нарушение концепции. Я не знаю точно, почему так происходит, но могу предположить, что у них одна команда, которая сегодня занимается исследованиями, а завтра в поте лица правит баги. Ну и чего они хотели добиться, внедряя технологию, которую сами же и не смогли осилить?

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

суббота, 29 июня 2013 г.

Эксепшены в Task'ах

Сегодня расскажу о замечательных индусах из Microsoft, которые вначале делают, а потом думают.

Конкретно речь пойдёт про Таски. Не буду про них расписывать, ибо не это тема сегодняшнего поста. Вкратце, это такие треды на стероидах с вкусными и удобными фичам.

Одна из фич, это проброс эксепшенов наружу. Примерно так:

var t = new Task(() => { throw new Exception(); });
t.Start();
// do something
try
{
 t.Wait();
}
catch (AggregateException)
{
 Console.WriteLine("Exception occurred");
 throw;
}

Т.е. мы что-то выполняем в отдельном потоке, в это время занимаемся своими вещами, а потом убеждаемся, что таск закончился и ловим исключение, которое за нас обернули в AggregateException (настоящее скрыто внутри его).
Т.е. получается вполне прикольная фича, можно честно ловить исключения из других потоков в то время, когда мы знаем, как их обработать. И этим можно активно пользоваться (например, скрывая всю параллельную работу внутри метода, но пробрасывая исключения наружу).

Но есть маленький нюанс. Эксепшен ведь пробрасывается, когда от таска что-то ждут (результат, или просто завершение). В стандартной терминологии это называется observable. Т.е. таск должен быть наблюдаемым. А что если мы запустили и забыли (или забили)?

new Task(() => { throw new Exception(); }).Start();

Получается, что эксепшен куда-то потеряется? Как бы не так! Доблестные спецы из Microsoft подумали, и придумали бросать исключение в деструкторе. Оцените изящество этого решения: нарушает все вменяемые стандарты кодирования, приводит к падению приложения, и выдаёт ошибки в то время и в том месте, где их отловить невозможно вообще. Супер!

Наверное, они решили, что раз исключение в обычном треде вызывает падение приложения, то и тут надо. Только забыли про это маленькое отличие с исключениями: если мы хотим сделать безопасным обычный тред, нам достаточно написать try/catch и все станут счастливы (всё равно никто за нас ошибки не обработает). А случае с тасками, кидать исключение изнутри наружу можно и местами иногда полезно. Но получается, что за этими тасками приходится следить как за маленькими детьми, хотя нам вполне может быть глубоко наплевать в данном месте на результат конкретной операции.

Решений данной проблемы в принципе можно придумать несколько (различные врапперы, следить за использованием тасков), одно из достаточно красивых такое:

public static Task IgnoreErrors(this Task t)
{
 t.ContinueWith(x => { var e = x.Exception; }, TaskContinuationOptions.OnlyOnFaulted);
 return t;
}

private static void DoTask()
{
 new Task(() => { throw new Exception(); }).IgnoreErrors().Start();
}

Т.е. мы создаём extension-метод, который прикрепляет к нашей таске продолжение (continuation), в котором мы берём значение свойства Exception (это обязательно надо сделать! именно так таска становится опять наблюдаемой (observable)), и на этом успокаиваем систему.

Задача решена, и надеюсь, что у вас она вызовет мата меньше чем у меня в своё время, когда я попался на такую проблему. А попался я на неё ещё по одной причине.

Бонус

Я вначале не зря писал, что в Microsoft вначале сделали, а потом начали думать. А подумав, они поняли, что поведение уж больно идиотское и убивать всё приложение никому не нужно. И в 4.5 изменили логику, так что для 4.5 уже мой пост неактуален.

Но без нюансов у Microsoft не обходится, ибо 4.5 по факту подменяет собой 4.0. Сюрприз! Т.е. установив 4.5, все приложения, написанные под 4.0 начинают по факту работать на 4.5, и слегка по-другому. Например, в данном случае, ошибка уже не появится (попадаются и некоторые другие различия в поведении, но это уж слишком выраженное). Вернуть старое поведение можно конфигом, но кто же заморачивается чтением всяких безумных и бесполезных настроек?

Т.е. вы как разработчик поставили все апдейты, написали приложение, протестировали в хвост и в гриву, а падает оно только у клиента. Ибо у клиента стоит Windows Server 2003, и ваше приложение должно с ним работать, и даже работает, только падает. Иногда. С непонятным стэктрейсом. И вы пытаетесь найти хвосты и поправить всё это безобразие.

Иногда просто хочется убиться головой об стену от таких гениальных поворотов сюжета.

вторник, 28 мая 2013 г.

Яндекс, ты пьян, иди домой!

Не силён в географии, и не факт что я ниже не займусь полным бредом, но Яндекс Карты взрывают мозг.
Вот кусок схемы дорог:

Это трасса М8, которая судя по схеме идёт через Лисавы, Тириброво и далее. Вроде всё в порядке.
Увеличиваем схему на один шаг.

Видно разницу? Если сразу не заметили, то распишу: через Лисавы и Тириброво уже идёт Ярославское шоссе, а трасса М8 неожиданно оказывается южнее.

WAT????
Т.е. на разных масштабах у Яндекса разные картографические данные. Как так?

При этом маршруты судя по всему, Яндекс строит исходя из первого варианта, в дальнейшем предлгая проехать через кусты и разделительную полосу.

Ну и как можно доверять яндесу в прокладке маршутов? При этом, что удивительно, но у Гугла всё гораздо лучше.