Допустим, что есть некий массив данных, и с ним можно что-нибудь делать. Например это большое количество .pdf-файлов, а делать будем поиск в них текста. Чтобы что-нибудь кешировалось, долго работало, вообще жило своей жизнью, нужно это выделить в отдельный процесс, жизнью которого можно управлять. Т.е. из веб-интерфейса запускаем запрос, он начинает выполняться, а мы потом через сутки смотрим, чем всё закончилось. У приложения тогда три части - JavaScript, который “делает красиво”, REST-API и web-прослойка, которая помогает джаваскрипту, высылая ему JSON, и запрашивая данные у фонового приложения. И фоновое приложение, которое долго работает.
Фоновое приложение можно сделать как минимум тремя способами: при помощи OpenRC, при помощи Systemd, и при помощи DBus. Первый способ отбросим как устаревший, как выбрать между вторым и третьим мне не ясно. Я бы выбрал третий, потому что так с этим сервисом могло бы связаться и десктопное приложение, но: 1) а будет ли DBus работать не на той же машине, а через соединение по локальной сети? (или через vpn); 2) пользователи, вероятно, имеют мало представления о том, как управлять DBus-сервисами, всё же systemd привычнее и задокументированнее. Если бы встал вопрос, как делать приложение для индексирования внешнего интернета, я бы без сомнений создавал бы systemd-сервис. Надо запустить? понятно как. Надо посмотреть статус и логи? Понятно как.
Systemd останавливает сервис при помощи SIGTERM.
(в статье есть чудесные мелкие детали вроде SuccessExitStatus=143
)
public class MyJavaService {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Обработка SIGTERM...");
// Здесь можно добавить код для очистки ресурсов или других действий перед завершением
}
});
System.out.println("Обработчик выключения добавлен.");
// Основной цикл работы сервиса
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Но не вполне ясно, зачем столько разных нитей в этом вопросе - How to process SIGTERM signal gracefully in Java? - Stack Overflow
Дальше, по-идее, надо открывать порт и слушать его.
ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();
Запускать нить, в ней принимать запрос, обрабатывать и формировать ответ.
Наверняка надо прочитать раздел про многопоточность в Java в каком-нибудь учебнике, потому что слов много непонятных.
«ExecutorService
из пакета java.util.concurrent
позволит создать пул потоков, который будет обрабатывать каждый входящий запрос в отдельном потоке, что обеспечит асинхронную обработку запросов.»
static ExecutorService executor = Executors.newFixedThreadPool(10); // Создаем пул потоков
...
while (true)
{
Socket client = server.accept(); // Принимаем соединение от клиента
executor.execute(new ClientHandler(client)); // Обрабатываем клиента в отдельном потоке
}
Но буду копать DBus, из любопытства, чтобы горизонты незнания расширялись. DBus может работать через локальную сеть, это требует корректной настройки listen
команд в конфигурационном файле dbus-daemon
. Можно ещё использовать приложение dbus-daemon-proxy
, которое слушает сокет и перенаправляет соединения к локальному dbus-daemon
. Или можно прокидывать сокет через ssh.
«Когда вы указываете программу для запуска с dbus-launch
, он запускает экземпляр сессии D-Bus, устанавливает соответствующие переменные окружения, чтобы указанная программа могла найти шину, а затем выполняет указанную программу с указанными аргументами.»
DBus здесь хорош тем, что сокетами занимается он, и протокол уже определён, документация понаписана.
Активацию через DBus не рекомендуют:
http://jdebp.uk/Softwares/nosh/avoid-dbus-bus-activation.html