diff --git a/README.md b/README.md index b35ff78..7cd77d3 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ https://www.reddit.com/r/linux/comments/5rixe9/this_is_why_i_love_linux_hundreds - возможность показа десктопных уведомлений c помощью `notify-send`, с показом сигнала (`SIGTERM` или `SIGKILL`), который отправлен процессу, а также `Pid`, `oom_score`, `VmRSS`, `VmSwap`, которыми обладал процесс перед получением сигнала. - поддержка white, black, prefer и avoid списков с использованием Perl-compatible regular expressions - наличие `man` страницы +- возможность выполнения определенных команд как альтернатива отправке SIGTERM для избранных процессов (можно использовать для перезапуска демонов вместо завершения) - поддержка журналирования в отдельный файл - поддержка десктопных уведомлений о низком уровне доступной памяти - наличие установщика для пользователей `systemd` diff --git a/nohang b/nohang index 05f5158..7e89c80 100755 --- a/nohang +++ b/nohang @@ -411,26 +411,35 @@ def find_victim_and_send_signal(signal): vm_rss = 0 vm_swap = 0 - try_to_send = ' Preventing OOM: trying to send the {} signal to {},\n Pid: {}, Badness: {}, VmRSS: {} MiB, VmSwap: {} MiB'.format(sig_dict[signal], name, pid, oom_score, vm_rss, vm_swap) - print(try_to_send) + if name in etc_dict and signal is 15: + command = etc_dict[name] + etc_info = ' Process {} is a victim,\n Pid: {}, Badness: {}, VmRSS: {} MiB, VmSwap: {} MiB\n Execute command: {}'.format(name, pid, oom_score, vm_rss, vm_swap, command) + print(etc_info) + os.system(etc_dict[name]) + append_log(etc_info) - try: - os.kill(int(pid), signal) - send_result = ' Success' + else: + try_to_send = ' Preventing OOM: trying to send the {} signal to {},\n Pid: {}, Badness: {}, VmRSS: {} MiB, VmSwap: {} MiB'.format(sig_dict[signal], name, pid, oom_score, vm_rss, vm_swap) - if desktop_notifications: - send_notify(signal, name, pid, oom_score, vm_rss, vm_swap) + print(try_to_send) - except FileNotFoundError: - send_result = ' No such process' - except ProcessLookupError: - send_result = ' No such process' + try: + os.kill(int(pid), signal) + send_result = ' Success' - print(send_result) + if desktop_notifications: + send_notify(signal, name, pid, oom_score, vm_rss, vm_swap) - if logging: - append_log(try_to_send + '\n' + send_result) + except FileNotFoundError: + send_result = ' No such process' + except ProcessLookupError: + send_result = ' No such process' + + print(send_result) + + if logging: + append_log(try_to_send + '\n' + send_result) else: @@ -547,17 +556,40 @@ print(config) # парсинг конфига с получением словаря параметров +# conf_parameters_dict +# conf_restart_dict + try: with open(config) as f: + + # словарь с параметрами конфига config_dict = dict() + + # словарь с именами и командами для параметра execute_the_command + etc_dict = dict() + for line in f: + a = line.startswith('#') b = line.startswith('\n') c = line.startswith('\t') d = line.startswith(' ') - if not a and not b and not c and not d: + + etc = line.startswith('**') + + if not a and not b and not c and not d and not etc: a = line.split('=') config_dict[a[0].strip()] = a[1].strip() + + if etc: + a = line[2:].split('::') + etc_name = a[0].strip() + etc_command = a[1].strip() + if len(etc_name) > 15: + print('инвалид конфиг, длина имени процесса не должна превышать 15 символов\nExit') + exit() + etc_dict[etc_name] = etc_command + except PermissionError: print('PermissionError', conf_err_mess) exit() @@ -1087,6 +1119,9 @@ else: exit() +execute_the_command = conf_parse_bool('execute_the_command') + + ########################################################################## # получение уровней в кибибайтах @@ -1266,6 +1301,14 @@ if print_config: round(zram_max_warnings_mb), round(zram_max_warnings_percent, 1))) + print('\nX. EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL') + print('execute_the_command: {}'.format(execute_the_command)) + if execute_the_command: + print('\nPROCESS NAME COMMAND TO EXECUTE') + for key in etc_dict: + print('{} {}'.format(key.ljust(15), etc_dict[key])) + + ########################################################################## diff --git a/nohang.conf b/nohang.conf index 5b3e2a7..d2910c6 100644 --- a/nohang.conf +++ b/nohang.conf @@ -20,7 +20,7 @@ print_config = True Печатать ли результаты измерения доступной памяти. Допустимые значения: True и False -print_mem_check_results = False +print_mem_check_results = True Печатать ли время сна между проверками памяти и после отправки сигналов. Можно установить в значение True для дебага. @@ -94,8 +94,8 @@ rate_zram = 1 mem_min_sigterm = 8 % mem_min_sigkill = 4 % -swap_min_sigterm = 8 % -swap_min_sigkill = 4 % +swap_min_sigterm = 50 % +swap_min_sigkill = 20 % Задание общей доли zram в памяти, при превышении которой происходит отправка соответствующих сигналов. @@ -278,3 +278,30 @@ swap_min_warnings = 20% zram_max_warnings = 40 % +##################################################################### + + X. EXECUTE THE COMMAND INSTEAD OF SENDING THE SIGTERM SIGNAL + + Для процессов с определенным именем можно задать команду, + которая будет выполняться вместо отправки сигнала SIGTERM + процессу с соответствующим именем. + + Например, если процесс запущен как демон, то вместо + отправки SIGTERM можно выполнить команду перезапуска. + + Допустимые значения: True и False. + +execute_the_command = False + + Длина имени процесса не должна превышать 15 символов. + Синтаксис таков: строки, начинающиеся с **, считаются строками, + содержащими имена процессов и соотвестствующие команды для + перезапуска этих процессов. После имени процесса через двойное + двоеточие (::) следует команда. + Например: + ** mysqld :: systemctl restart mariadb.service & + ** php-fpm7.0 :: systemctl restart php7.0-fpm.service & + Амперсанд (&) в конце команды позволит nohang продолжить работу + не дожидаясь окончания выполнения команды. + +** processname :: some command &