barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

четверг, 30 июня 2016 г.

SLES 11 и внезапно пропадающий процесс WSO2 ESB

Есть SLES 11, на нем крутится WSO2 ESB 4.9.0. Периодически процесс WSO2 ESB просто пропадает, в логах самой шины никаких ошибок, как будто его просто кто-то кильнул. Возникло подозрение, что процесс киляет сама ОС из-за нехватки ОП. Идем в /var/log/warn, видим там:
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.048428] java invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
...
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.048618] 88800 total pagecache pages
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.048619] 53685 pages in swap cache
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.048620] Swap cache stats: add 8392477, delete 8338792, find 21248605/22043373
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.048622] Free swap  = 0kB
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.048631] Total swap = 1048572kB
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.057372] 1048560 pages RAM
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.057374] 35908 pages reserved
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.057375] 80915 pages shared
Jun 30 10:21:12 ESBint2-60141 kernel: [3866020.057376] 950754 pages non-shared

Jun 30 10:21:13 ESBint2-60141 kernel: [3866020.057588] Out of memory: Kill process 26797 (java) score 432 or sacrifice child
Jun 30 10:21:13 ESBint2-60141 kernel: [3866020.057707] Killed process 26797 (java) total-vm:3475068kB, anon-rss:2180320kB, file-rss:0kB
Сравниваем указанный в последней строчке pid со значением в файле wso2carbon.pid в директории установки WSO2 ESB - совпадает. Диагноз - шина убивается системой из-за нехватки физической памяти.

вторник, 21 июня 2016 г.

requirejs и управление браузерным кэшированием с помощью конфигурационного параметра urlArgs

Задача

В проекте, использующем requirejs, встала острая необходимость управлять кэшированием js-файлов браузером. Ситуация типичная: в приложении обновляется некоторый js-файл, но клиент продолжает пользоваться старой версией файла, т.к. браузер его закэшировал (в т.н. называемый Back/Forward Cache, или BFCache: http://www.pvsm.ru/javascript/61476). И пока кэш не просрочится, ситуация не изменится. Вот как данный случай выглядит в Firebug:


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

Решение

Конечно, управлять кэшированием можно на стороне сервера, с помощью заголовков Expires / Last-Modified / Cache-Control / Pragma. Но, во-первых, предлагаемый здесь способ более гибкий. А, во-вторых, если управлять кэшированием вы решили не на самом старте проекта, а лишь в какой-то момент его жизни после выхода в продакшен, вы никакими серверными махинациями не заставите браузер раскэшировать то, что он уже закэшировал ранее.
Итак, про requeirejs. Конфигурация requirejs имеет параметр urlArgs, позволяющий добавлять GET-аргументы к URL-ам, по которым загружаются js-файлы. Например, при задании этого параметры равным "v=1" файл formatter.js будет грузиться по URL'у formatter.js?v=1. В новых версиях requirejs есть возможность использовать функцию вместо статичной строки, но сейчас не об этом. Главное, что для браузера formatter.js и formatter.js?v=1 - различные  URL, и даже закешировав ранее файл formatter.js браузер все равно пойдет на сервер за formatter.js?v=1 (хотя, сервер, конечно, по обоим URL'ам выдаст один и тот же файл, т.к. это статичный ресурс и GET-параметры для него игнорируются).
При поиске решения я наткнулся на интересную статью: http://blog.johnnyreilly.com/2014/03/caching-and-cache-busting-with-requirejs.html. В ней приводится рекомендация по использованию параметра urlArgs для управления кэшированием, которую я успешно и применил. Автор предлагает 2 разных подхода для разработки и продуктивного развертывания проекта:
  • В процессе разработки удобно, когда вообще ничего не кэшируется, и любые правки на сервере сразу же попадают в браузер. В данном случае задаем параметр urlArgs равным "v=" +  (new Date()).getTime(). В итоге имеем при каждой загрузке страницы новые URL'ы, и браузер все js-файлы гарантированно загружает с сервера
  • В продуктивном развертывании необходим баланс между актуальностью файлов и потреблением сетевых ресурсов, так что вариант, описанный выше, не подходит: файлы на сервере меняются не часто, и на какой-то промежуток времени их все же хорошо было бы кэшировать. Здесь можно воспользоваться следующим подходом: устанавливаем параметр urlArgs  равным "v=<productVersion>", где <productVersion> - версия Вашего продукта (сайта). Т.о., при выпуске и установке в продуктив новой версии Вашего продукта все клиенты при первом обращении к сайту получат актуальные версии js-файлов, т.к. изменилась версия продукта, а, значит, и все URL-ы, по которым загружаются js-ки. Далее же, до выхода следующей версии, браузер может (и будет) спокойно кэшировать js-файлы, т.к. они гарантированно остаются неизменными.