Как написать службу на Java (под Linux)?

Допустим, что есть некий массив данных, и с ним можно что-нибудь делать. Например это большое количество .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