При остановке приложения с КМА, приложение должно вызвать метод КМА stop(). При этом КМА должен дать сигнал агентам для их аккуратного завершения и отправить конечный результат работы в МА. Завершение КМА состоит из 3х фаз.
1. На 1й фазе для всех активных НЗ устанавливаем AgentContext#isCanceled в true. Для всех SCHED ставим флаг "прерван". Отменяем задачу ожидания запуска сигналов для запуска SCHED-агентов, чтобы новые агенты не запускать.
Итераторы SCHED агентов должны перестать опрашивать очередные jms-сообщения. AsapAgentListener при получении сообщения не должен вызывать агент, а должен вызвать rollback() и закрыть свой JMSContext.
ASAP и SCHED агенты теперь не получат новых сообщений, но могут обрабатывать последнее.
2. На 2й фазе ждем 15 сек.
Агенты могут завершить обработку последнего сообщения без InterruptedException и закоммитить его.
Для завершенных SCHED шлем в МА статус прерывания на основании флага "прерван".
Для завершенных ASAP шлем в МА статус успешного завершения.
JMS-транзакции коммитим.
Если все агенты завершились ранее 15 сек, то прерываем фазу 2 и пропускаем фазу 3.
3. На 3й фазе принудительлно закрываем "зависших" агентов. Сначала для всех не завершенных SCHED вызываем Future.cancel(true). Затем для каждого не завершенного ASAP ставим флаг "прерван", вызываем thread.interrupt() и JMSContext.close() (т.к. JMSContext.close() блокируется в ожидании завершения ASAP-Listener). Но агенты могут всё ещё продолжить работать.
JMSContext для SCHED закрывается при выходе из агента.
Если получили любой эксепшен и установлен флаг "прерван", то шлем в МА статус "прерван". (Помимо InterruptedException могут быть ещё связанные с не возможностью закоммитить jms-транзакцию)
ASAP на этой фазе тоже могут завершится без эксепшена - шлем статус успешного завершения.