barbitoff programmer`s blog

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

вторник, 2 августа 2016 г.

SLES: добавление постоянного маршрута

Есть несколько способов, один из них:
  1. Создаем исполняемый файл в /etc/sysconfig/network/if-up.d/. Он будет выполняться при каждом поднятии интерфейса
  2. Прописываем в него команду добавления нужного маршрута, например:
    route add -host 10.1.1.2 gw 192.168.1.100

четверг, 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-файлы, т.к. они гарантированно остаются неизменными.

пятница, 22 апреля 2016 г.

Linux: подсчет числа потоков в приложении

Задача

Необходимо узнать, сколько потоков имеет на текущий момент то или иное запущенное приложение.

Решение
ps -eLf | grep <app_name> | wc -l
 , где <app_name> может быть именем исполняемого файла или любой другой строкой, которая может отличить интересующий процесс от других в выводе команды ps.

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

PostgreSQL: unrecognized configuration parameter "row_security" при восстановлении из SQL-дампа

Проблема

Сняли дамп с БД в текстовом формате, пытаемся восстановить, получаем ошибку:
ERROR: unrecognized configuration parameter "row_security"
SQL-состояние: 42704
Версия СУБД, на которую накатывался дамп, совпадает с версией СУБД, откуда он снимался.

Решение

Если посмотреть внимательно на sql-ник дампа, в начале можно заметить строки:
-- Dumped from database version 9.4.4
-- Dumped by pg_dump version 9.5.0
, говорящие о том, что дамп снимался версией pg_dump 9.5.0. Она и добавила в дамп строчку:
SET row_security = off;
, не поддерживаемую СУБД 9.4.4. Удаляем эту строчку - дамп успешно накатывается.

понедельник, 11 апреля 2016 г.

Java: подмена HTTP-заголовка, выдаваемого сервлетом / JSP-страницей

Задача

Есть некий сервлет (или JSP-страница), недоступный для модификации. Необходимо подменить один из выдаваемых сервлетом HTTP-заголоков. Например, сервлет выдает для скачивания некий файл. Необходимо подменить имя этого файла, т.е. заголовок "Content-Disposition".

Решение

Делаем jsp-страничку, которая будет служить своего рода прокси-объектом для оригинального сервлета, в ней делаем следующее:
<%
javax.servlet.http.HttpServletResponseWrapper wrappedResponse = new javax.servlet.http.HttpServletResponseWrapper(response) {
public void setHeader(String name, String value) {
if(name.equals("My-Header")) {
value = "my_value";
}
super.setHeader(name, value);
} public void addHeader(String name, String value) {
if(name.equals("My-Header")) {
value = "my_value";
}
super.addHeader(name, value);
} };
request.getRequestDispatcher("MyServlet").forward(request, wrappedResponse);
%>
Т.е. заворачиваем объект оригинального HTTP-ответа во wrapper, переопределяем методы установки заголовков, после чего выполняем forward на целевой сервлет. В итоге значение заголовка HTTP-заголовка "My-Header", генерируемого сервлетом, развернутым по относительному пути "MyServlet", будет заменено на "my_value".