SlideShare a Scribd company logo
JavaDay'14
Кирилл Голоднов 
Java-разработчик в Яндекс.Метрика 
О бесконечно долгой работе дочерних процессов Java- приложения
3 
Содержание 
•Постановка задачи и описание проблемы 
•Пример воспроизводимого тест-кейса 
•Анализ «зависания» тестового процесса – почему это происходит и как это исправить 
•Почему «зависают» процессы, когда ваш код в этом точно не виноват, и как с этим бороться
4 
Постановка проблемы 
•Есть сервис, который обрабатывает файлы, используя запуск внешних нативных процессов. 
•Проблема: на некоторых файлах дочерний процесс зависает.
5 
Маленькое наблюдение 
•Зависают те процессы, которые выводят в stdout много информации
6 
Как работать с процессом 
•Чаще всего, с процессом работают так: 
Process process = new ProcessBuilder(cmd) 
.environment(envp) 
.directory(dir) 
.start(); 
process.waitFor(); 
if (process.exitValue() == 0) { 
// Getting out and error streams of this process 
InputStream output = process.getInputStream(); 
InputStream error = process.getErrorStream(); 
// Skipped: processing data in process streams 
} else { 
// Skipped: external process returned non-zero code… 
} 
•Вместо ProcessBuilder в данном случае можно просто Runtime.getRuntime().exec(cmd, envp, dir).
7 
Тестовый процесс 
~$ s=$(printf "%-20s" '~') ; echo "${s// /'~'}" 
~~~~~~~~~~~~~~~~~~~~
8 
Тестовый дочерний процесс 
String[] cmd = { 
"/bin/bash", 
"-c", 
"s=$(printf "%-" + n + "s" '~') ; echo "${s// /'~'}"" 
}; 
Process process = new ProcessBuilder(cmd).start(); 
process.waitFor();
9 
Результаты работы процесса 
•Процесс отрабатывает для n = 10, 20, 30, 40, 1000, 10000. 
•Процесс зависает для n = 100000, 200000, 1000000 и т.д.
10 
Что значит «процесс зависает»? 
•Утверждение «процесс зависает для n = 100000, 1000000» является сомнительным как минимум по трём причинам: 
- Проблема остановки неразрешима (Тьюринг, 1936) 
- Процесс просто работает долго? Swapping и/или внутренняя жизнь ОС, внезапно возникшая внешняя нагрузка на сервер и т.д. 
- Процесс-таки отработал (и очень быстро), а Java не смогла получить его поток на чтение (in.readLine())?
11 
Процесс «зависает»? 
•Правильно написать: 
«Исходное Java-приложение испытывает проблемы с производительностью для n = 100000, 1000000, а именно – не успевает отработать за k секунд».
12 
Процесс в ps 
•Это снимок примерно сразу после вызова внешнего процесса: 
~$ ps -ef | grep bash 
kirill 4158 4148 95 01:08 pts/1 00:00:08 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
13 
Процесс в ps 
•Это снимок через некоторое время: 
~$ ps -ef | grep bash 
kirill 4158 4148 10 01:08 pts/1 00:00:14 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
14 
Процесс в top 
•Это снимок примерно сразу после вызова внешнего процесса: 
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 
4158 kirill 20 0 6196 2032 1148 R 94.8 0.1 0:12.39 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
15 
Процесс в top 
•Это снимок через некоторое время: 
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 
4158 kirill 20 0 6196 1872 1172 S 0.0 0.1 0:14.06 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
16 
Процесс в /proc/…/stat 
~$ less /proc/4158/stat 
4158 (bash) S 4148 4148 …
17 
Граничное значение параметра n 
•Процесс в состоянии sleeping (не использует CPU), который непонятно что делает. 
•Граничное значение n – это n = 65535 (двоичный поиск).
18 
Источник проблемы 
•Буфер ограниченного размера, через который общаются процессы.
19 
Что делать с процессом в Java? 
•Надо вычитывать stdout дочернего процесса во время работы. 
•Желательно избежать вызова process.waitFor().
20 
IOUtils.copy из Apache commons-io 
public static long copyLarge(InputStream input, OutputStream output, 
byte[] buffer) throws IOException { 
long count = 0; 
int n = 0; 
while (EOF != (n = input.read(buffer))) { 
output.write(buffer, 0, n); 
count += n; 
} 
return count; 
}
21 
Копируем байты из stdout 
Process process = new ProcessBuilder(cmd).start(); 
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
IOUtils.copy(process.getInputStream(), outputStream); 
process.waitFor();
22 
Забыли про stderr 
String[] cmd = { 
"/bin/bash", 
"-c", 
"s=$(printf "%-" + n + "s" '~') ; echo "${s// /'~'}" >&2" }; 
Process process = new ProcessBuilder(cmd).start(); 
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
IOUtils.copy(process.getInputStream(), outputStream); 
process.waitFor();
23 
IOUtils.copy 
•Отказываемся от IOUtils.copy. 
•Надо придумать что-то другое.
24 
«Новый» метод 
•В Java 8 в java.lang.Process появился «новый» метод: 
public boolean isAlive() { 
try { 
exitValue(); 
return false; 
} catch (IllegalThreadStateException e) { 
return true; 
} 
} 
•В java.lang.UNIXProcess этот метод переопределяется: 
@Override 
public synchronized boolean isAlive() { 
return !hasExited; 
}
25 
Использование «нового» метода 
•Пока процесс жив, вычитываем неблокирующим чтением его stdout и stderr. 
•Между парами чтений делаем паузы.
26 
Неблокирующее перемещение байтов 
private static int moveBytes(InputStream src, OutputStream dst, 
byte[] buffer) throws IOException { 
if (src.available() > 0) { 
int read = src.read(buffer); 
if (read > 0) { 
dst.write(buffer, 0, read); 
} 
return read; 
} else { 
return 0; 
} 
}
27 
Использование moveBytes 
final byte[] buffer = new byte[1 << 15]; 
while (process.isAlive()) { 
while (Math.max( 
moveBytes(process.getInputStream(), outputStream, buffer), 
moveBytes(process.getErrorStream(), errorStream, buffer)) > 0) { 
} 
Thread.sleep(10); 
} 
// Process has terminated, let's read remain data from process: 
while (moveBytes(process.getInputStream(), outputStream, buffer) > 0) { 
} 
while (moveBytes(process.getErrorStream(), errorStream, buffer) > 0) { 
}
28 
Чтение через дополнительные потоки 
Pair<InputStream, ByteArrayOutputStream>[] pairs = new Pair[]{ 
Pair.of(process.getInputStream(), new ByteArrayOutputStream()), 
Pair.of(process.getErrorStream(), new ByteArrayOutputStream()) 
}; 
for (Pair<InputStream, ByteArrayOutputStream> pair : pairs) { 
executor.submit(() -> IOUtils.copy(pair.getKey(), pair.getValue())); 
} 
process.waitFor();
29 
Без pipe проблемы нет 
•Этот процесс работает нормально: 
new ProcessBuilder(cmd). 
redirectOutput(ProcessBuilder.Redirect.INHERIT). 
redirectError(ProcessBuilder.Redirect.INHERIT). 
start(); 
•Если использовать вместо INHERIT – WRITE/APPEND, то тоже всё хорошо.
30 
Пойдём далее 
•Пусть проблема с буфером уже решена. 
•Любой процесс, получающий и обрабатывающий данные из интернета, может зависнуть с достаточно большой вероятностью.
31 
Пример с phantomjs 
~$ ps -ef | grep phantomjs 
metrika 2516 789 0 Sep17 ? 00:00:00 /usr/lib/phantomjs … 
metrika 5930 2516 0 Sep17 ? 00:00:00 /usr/lib/phantomjs … 
metrika 16135 1 0 May19 ? 00:00:00 /usr/lib/phantomjs … 
metrika 17031 16135 0 May19 ? 00:00:00 /usr/lib/phantomjs …
32 
Пример с urllib.open try: usock = urllib.urlopen(c_url) except: out.write('Error while opening ' + c_url)
33 
Причины зависания процессов 
•Ошибки в программном коде внешних программ и библиотек. 
•Ошибки того, кто вызывает процесс.
34 
Последствия зависания процессов 
•Перестаёт контролироваться Java-процессом. 
•Если таких процессов много, растёт длина CPU Run Queue. Увеличиваются затраты памяти, возможен swapping.
35 
Пример с ZooKeeper 
if (lock.acquire(5, TimeUnit.SECONDS)) { 
try { 
<hanging or looping process> 
} finally { 
lock.release(); 
} 
}
36 
Что же делать? 
•Построить свой алгоритм, который будет определять, завис ли процесс, на основе его состояний (D/R/S/T/Z). 
•Снимать процесс по таймауту, из Java.
37 
Apache commons-exec 
•Библиотека от Apache для работы с процессами. 
•Совместима с JDK 1.3.
38 
commons-exec: CommandLine 
CommandLine cmd = CommandLine.parse("/bin/bash"); 
// Failed to parse string: "/bin/bash -c 'echo 1'" 
cmd.addArguments(new String[] { "-c", 
"s=$(printf "%-" + n + "s" '~') ; echo "${s// /'~'}"" }, 
false); 
DefaultExecutor executor = new DefaultExecutor(); 
executor.setExitValue(0);
39 
commons-exec: PumpStreamHandler 
ByteArrayOutputStream out = new ByteArrayOutputStream(); 
ByteArrayOutputStream err = new ByteArrayOutputStream(); 
PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(out, err); 
executor.setStreamHandler(pumpStreamHandler);
40 
commons-exec: ExecuteWatchdog 
ExecuteWatchdog watchdog = new ExecuteWatchdog(10000); 
executor.setWatchdog(watchdog); 
executor.execute(cmd);
41 
Apache commons-exec 
•Справляется с большинством задач, связанных с процессами. 
•Хорошо спроектирована по архитектуре кода.
42 
Apache commons-exec 
•Работает через Process.destroy(). 
•От ExecuteWatchdog сложно наследоваться.
43 
Введём метод destroyForcibly() 
private static boolean destroyForcibly(Process process) { 
if (process != null && process.isAlive()) { 
process.destroyForcibly(); 
return true; 
} 
return false; 
}
44 
Используем метод destroyForcibly() 
try { 
// Skipped: process initialization 
while (process.isAlive() && (timeout <= 0 || System.currentTimeMillis() < finish)) { 
// Skipped: get data from process streams (stdout and stderr) 
} 
// Skipped: get data from process streams for the last time 
if (destroyForcibly(process)) { 
throw new TimeoutException("Process " + Arrays.toString(cmd) 
+ " has not finished its work and was destroyed" 
+ " after " + (System.currentTimeMillis() - start) + " ms"); 
} 
} catch (InterruptedException | IOException | RuntimeException | Error e) { 
destroyForcibly(process); 
throw e; 
}
Кирилл Голоднов 
Java-разработчик 
kyrylhol@yandex-team.ru 
http://kyryloholodnov.wordpress.com

More Related Content

PDF
Использование юнит-тестов для повышения качества разработки
PPT
бегун
PDF
Семь тысяч Rps, один go
PDF
Reform: путь к лучшему ORM
PPTX
PowerShell
PDF
Асинхронный JavaScript
PPTX
Developing highload servers with Java
PPTX
Everything you wanted to know about writing async, high-concurrency HTTP apps...
Использование юнит-тестов для повышения качества разработки
бегун
Семь тысяч Rps, один go
Reform: путь к лучшему ORM
PowerShell
Асинхронный JavaScript
Developing highload servers with Java
Everything you wanted to know about writing async, high-concurrency HTTP apps...

What's hot (20)

PDF
Практика Lock-free. RealTime-сервер
PDF
Мониторинг ожиданий в PostgreSQL / Курбангалиев Ильдус (Postgres Professional)
PDF
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
PPT
бегун
PDF
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
PPTX
Tdd webpack + testem + mocha + chai
PDF
JPoint 2016 - Etudes of DIY Java profiler
PDF
Caching data outside Java Heap and using Shared Memory in Java
PDF
Отладка и устранение проблем в PostgreSQL Streaming Replication.
PDF
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
PDF
Михаил Давыдов - JavaScript. Асинхронность
PDF
Web осень 2013 лекция 2
PDF
Библиотеки для передачи данных (Lecture 13 – multithreading, network (libs))
PDF
PostgreSQL Vacuum: Nine Circles of Hell
PDF
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
PDF
Михаил Давыдов — JavaScript: Асинхронность
PDF
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
PDF
Java 8 puzzlers
PDF
RDSDataSource: Чистые тесты на Swift
PPTX
Asynchrony and coroutines
Практика Lock-free. RealTime-сервер
Мониторинг ожиданий в PostgreSQL / Курбангалиев Ильдус (Postgres Professional)
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
бегун
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Tdd webpack + testem + mocha + chai
JPoint 2016 - Etudes of DIY Java profiler
Caching data outside Java Heap and using Shared Memory in Java
Отладка и устранение проблем в PostgreSQL Streaming Replication.
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
Михаил Давыдов - JavaScript. Асинхронность
Web осень 2013 лекция 2
Библиотеки для передачи данных (Lecture 13 – multithreading, network (libs))
PostgreSQL Vacuum: Nine Circles of Hell
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
Михаил Давыдов — JavaScript: Асинхронность
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
Java 8 puzzlers
RDSDataSource: Чистые тесты на Swift
Asynchrony and coroutines
Ad

Similar to JavaDay'14 (6)

PPTX
Операционные системы 2015, лекция № 4
PDF
Операционные системы
DOCX
Нурафшанский филлиал Ташкентского Университета Информационных Технологий имен...
PDF
Linux Kernel Processes
PDF
Java 9: what is there beyond modularization
PDF
Lecture1: Introduction to Parallel Computing
Операционные системы 2015, лекция № 4
Операционные системы
Нурафшанский филлиал Ташкентского Университета Информационных Технологий имен...
Linux Kernel Processes
Java 9: what is there beyond modularization
Lecture1: Introduction to Parallel Computing
Ad

JavaDay'14

  • 2. Кирилл Голоднов Java-разработчик в Яндекс.Метрика О бесконечно долгой работе дочерних процессов Java- приложения
  • 3. 3 Содержание •Постановка задачи и описание проблемы •Пример воспроизводимого тест-кейса •Анализ «зависания» тестового процесса – почему это происходит и как это исправить •Почему «зависают» процессы, когда ваш код в этом точно не виноват, и как с этим бороться
  • 4. 4 Постановка проблемы •Есть сервис, который обрабатывает файлы, используя запуск внешних нативных процессов. •Проблема: на некоторых файлах дочерний процесс зависает.
  • 5. 5 Маленькое наблюдение •Зависают те процессы, которые выводят в stdout много информации
  • 6. 6 Как работать с процессом •Чаще всего, с процессом работают так: Process process = new ProcessBuilder(cmd) .environment(envp) .directory(dir) .start(); process.waitFor(); if (process.exitValue() == 0) { // Getting out and error streams of this process InputStream output = process.getInputStream(); InputStream error = process.getErrorStream(); // Skipped: processing data in process streams } else { // Skipped: external process returned non-zero code… } •Вместо ProcessBuilder в данном случае можно просто Runtime.getRuntime().exec(cmd, envp, dir).
  • 7. 7 Тестовый процесс ~$ s=$(printf "%-20s" '~') ; echo "${s// /'~'}" ~~~~~~~~~~~~~~~~~~~~
  • 8. 8 Тестовый дочерний процесс String[] cmd = { "/bin/bash", "-c", "s=$(printf "%-" + n + "s" '~') ; echo "${s// /'~'}"" }; Process process = new ProcessBuilder(cmd).start(); process.waitFor();
  • 9. 9 Результаты работы процесса •Процесс отрабатывает для n = 10, 20, 30, 40, 1000, 10000. •Процесс зависает для n = 100000, 200000, 1000000 и т.д.
  • 10. 10 Что значит «процесс зависает»? •Утверждение «процесс зависает для n = 100000, 1000000» является сомнительным как минимум по трём причинам: - Проблема остановки неразрешима (Тьюринг, 1936) - Процесс просто работает долго? Swapping и/или внутренняя жизнь ОС, внезапно возникшая внешняя нагрузка на сервер и т.д. - Процесс-таки отработал (и очень быстро), а Java не смогла получить его поток на чтение (in.readLine())?
  • 11. 11 Процесс «зависает»? •Правильно написать: «Исходное Java-приложение испытывает проблемы с производительностью для n = 100000, 1000000, а именно – не успевает отработать за k секунд».
  • 12. 12 Процесс в ps •Это снимок примерно сразу после вызова внешнего процесса: ~$ ps -ef | grep bash kirill 4158 4148 95 01:08 pts/1 00:00:08 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
  • 13. 13 Процесс в ps •Это снимок через некоторое время: ~$ ps -ef | grep bash kirill 4158 4148 10 01:08 pts/1 00:00:14 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
  • 14. 14 Процесс в top •Это снимок примерно сразу после вызова внешнего процесса: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4158 kirill 20 0 6196 2032 1148 R 94.8 0.1 0:12.39 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
  • 15. 15 Процесс в top •Это снимок через некоторое время: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4158 kirill 20 0 6196 1872 1172 S 0.0 0.1 0:14.06 /bin/bash -c s=$(printf "%-100000s" '~') ; echo "${s// /'~'}"
  • 16. 16 Процесс в /proc/…/stat ~$ less /proc/4158/stat 4158 (bash) S 4148 4148 …
  • 17. 17 Граничное значение параметра n •Процесс в состоянии sleeping (не использует CPU), который непонятно что делает. •Граничное значение n – это n = 65535 (двоичный поиск).
  • 18. 18 Источник проблемы •Буфер ограниченного размера, через который общаются процессы.
  • 19. 19 Что делать с процессом в Java? •Надо вычитывать stdout дочернего процесса во время работы. •Желательно избежать вызова process.waitFor().
  • 20. 20 IOUtils.copy из Apache commons-io public static long copyLarge(InputStream input, OutputStream output, byte[] buffer) throws IOException { long count = 0; int n = 0; while (EOF != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; }
  • 21. 21 Копируем байты из stdout Process process = new ProcessBuilder(cmd).start(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); IOUtils.copy(process.getInputStream(), outputStream); process.waitFor();
  • 22. 22 Забыли про stderr String[] cmd = { "/bin/bash", "-c", "s=$(printf "%-" + n + "s" '~') ; echo "${s// /'~'}" >&2" }; Process process = new ProcessBuilder(cmd).start(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); IOUtils.copy(process.getInputStream(), outputStream); process.waitFor();
  • 23. 23 IOUtils.copy •Отказываемся от IOUtils.copy. •Надо придумать что-то другое.
  • 24. 24 «Новый» метод •В Java 8 в java.lang.Process появился «новый» метод: public boolean isAlive() { try { exitValue(); return false; } catch (IllegalThreadStateException e) { return true; } } •В java.lang.UNIXProcess этот метод переопределяется: @Override public synchronized boolean isAlive() { return !hasExited; }
  • 25. 25 Использование «нового» метода •Пока процесс жив, вычитываем неблокирующим чтением его stdout и stderr. •Между парами чтений делаем паузы.
  • 26. 26 Неблокирующее перемещение байтов private static int moveBytes(InputStream src, OutputStream dst, byte[] buffer) throws IOException { if (src.available() > 0) { int read = src.read(buffer); if (read > 0) { dst.write(buffer, 0, read); } return read; } else { return 0; } }
  • 27. 27 Использование moveBytes final byte[] buffer = new byte[1 << 15]; while (process.isAlive()) { while (Math.max( moveBytes(process.getInputStream(), outputStream, buffer), moveBytes(process.getErrorStream(), errorStream, buffer)) > 0) { } Thread.sleep(10); } // Process has terminated, let's read remain data from process: while (moveBytes(process.getInputStream(), outputStream, buffer) > 0) { } while (moveBytes(process.getErrorStream(), errorStream, buffer) > 0) { }
  • 28. 28 Чтение через дополнительные потоки Pair<InputStream, ByteArrayOutputStream>[] pairs = new Pair[]{ Pair.of(process.getInputStream(), new ByteArrayOutputStream()), Pair.of(process.getErrorStream(), new ByteArrayOutputStream()) }; for (Pair<InputStream, ByteArrayOutputStream> pair : pairs) { executor.submit(() -> IOUtils.copy(pair.getKey(), pair.getValue())); } process.waitFor();
  • 29. 29 Без pipe проблемы нет •Этот процесс работает нормально: new ProcessBuilder(cmd). redirectOutput(ProcessBuilder.Redirect.INHERIT). redirectError(ProcessBuilder.Redirect.INHERIT). start(); •Если использовать вместо INHERIT – WRITE/APPEND, то тоже всё хорошо.
  • 30. 30 Пойдём далее •Пусть проблема с буфером уже решена. •Любой процесс, получающий и обрабатывающий данные из интернета, может зависнуть с достаточно большой вероятностью.
  • 31. 31 Пример с phantomjs ~$ ps -ef | grep phantomjs metrika 2516 789 0 Sep17 ? 00:00:00 /usr/lib/phantomjs … metrika 5930 2516 0 Sep17 ? 00:00:00 /usr/lib/phantomjs … metrika 16135 1 0 May19 ? 00:00:00 /usr/lib/phantomjs … metrika 17031 16135 0 May19 ? 00:00:00 /usr/lib/phantomjs …
  • 32. 32 Пример с urllib.open try: usock = urllib.urlopen(c_url) except: out.write('Error while opening ' + c_url)
  • 33. 33 Причины зависания процессов •Ошибки в программном коде внешних программ и библиотек. •Ошибки того, кто вызывает процесс.
  • 34. 34 Последствия зависания процессов •Перестаёт контролироваться Java-процессом. •Если таких процессов много, растёт длина CPU Run Queue. Увеличиваются затраты памяти, возможен swapping.
  • 35. 35 Пример с ZooKeeper if (lock.acquire(5, TimeUnit.SECONDS)) { try { <hanging or looping process> } finally { lock.release(); } }
  • 36. 36 Что же делать? •Построить свой алгоритм, который будет определять, завис ли процесс, на основе его состояний (D/R/S/T/Z). •Снимать процесс по таймауту, из Java.
  • 37. 37 Apache commons-exec •Библиотека от Apache для работы с процессами. •Совместима с JDK 1.3.
  • 38. 38 commons-exec: CommandLine CommandLine cmd = CommandLine.parse("/bin/bash"); // Failed to parse string: "/bin/bash -c 'echo 1'" cmd.addArguments(new String[] { "-c", "s=$(printf "%-" + n + "s" '~') ; echo "${s// /'~'}"" }, false); DefaultExecutor executor = new DefaultExecutor(); executor.setExitValue(0);
  • 39. 39 commons-exec: PumpStreamHandler ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream(); PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(out, err); executor.setStreamHandler(pumpStreamHandler);
  • 40. 40 commons-exec: ExecuteWatchdog ExecuteWatchdog watchdog = new ExecuteWatchdog(10000); executor.setWatchdog(watchdog); executor.execute(cmd);
  • 41. 41 Apache commons-exec •Справляется с большинством задач, связанных с процессами. •Хорошо спроектирована по архитектуре кода.
  • 42. 42 Apache commons-exec •Работает через Process.destroy(). •От ExecuteWatchdog сложно наследоваться.
  • 43. 43 Введём метод destroyForcibly() private static boolean destroyForcibly(Process process) { if (process != null && process.isAlive()) { process.destroyForcibly(); return true; } return false; }
  • 44. 44 Используем метод destroyForcibly() try { // Skipped: process initialization while (process.isAlive() && (timeout <= 0 || System.currentTimeMillis() < finish)) { // Skipped: get data from process streams (stdout and stderr) } // Skipped: get data from process streams for the last time if (destroyForcibly(process)) { throw new TimeoutException("Process " + Arrays.toString(cmd) + " has not finished its work and was destroyed" + " after " + (System.currentTimeMillis() - start) + " ms"); } } catch (InterruptedException | IOException | RuntimeException | Error e) { destroyForcibly(process); throw e; }
  • 45. Кирилл Голоднов Java-разработчик kyrylhol@yandex-team.ru http://kyryloholodnov.wordpress.com