TGViewer
Разработка с Дарьей Матвеевой Разработка с Дарьей Матвеевой @system_design_explained · 72 subscribers
Post #39 243
Возникла проблема при старте сервиса - долго не отвечают heathchecks сервиса в openshift.
Для данного сервиса healthchecks в Openshift проверяли liveness и readiness эндпойнты актуатора в Spring boot, и проблема оказалась в readiness probe.
Выяснилось, что при старте сервиса запускается продолжительный по времени метод формирования отчета, который сохраняется в БД в ожидании, когда его считает другой сервис.
Возник вопрос, насколько актуальна readiness probe для сервиса, который не принимает входящих запросов и лишь формирует отчет? Однако оказалось, что отключить ее нет возможности.
Поэтому следующим шагом стал разбор того, что происходит при старте.
Метод формирования отчета запускался с помощью аннотации:
@EventListener(AppricationReadyEvent.class)
public void generate() {
//логика создания отчета
}


В документации к классу AppricationReadyEvent сказано:
Event published as late as conceivably possible to indicate that the application is ready to service requests.

В документации к классу ReadinessState:
"Readiness" state of the application.
An application is considered ready when it's live and willing to accept traffic. "Readiness" failure means that the application is not able to accept traffic and that the infrastructure should stop routing requests to it.


Выглядит логично, что AppricationReadyEvent должен быть опубликован после того, как readiness probe станет UP.
Посмотрим, когда выставляет статус UP.

В методе SpingApplication.run(...), после создания, инициализации и подготовки контекста идет вызов listeners.ready(...)
  public ConfigurableApplicationContext run(String... args) {
...
try {
...
context = createApplicationContext();
...
}
try {
if (context.isRunning()) {
listeners.ready(context, startup.ready());
}
}
...
}

Здесь вызывается EventPublishingRunListener#ready, который и выставляет статус readiness probe в UP:

org.springframework.boot.context.event.EventPublishingRunListener#ready
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}

А context.publishEvent в свою очередь вызывает

org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent
@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
...
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null && listener.supportsAsyncExecution()) {
try {
executor.execute(() -> invokeListener(listener, event));
}...
}


invokeListeners(...) - как раз приводит к вызову нашего метода generate, помеченного аннотацией @EventListener(AppricationReadyEvent.class)
Поэтому, пока он не завершится, readiness probe не будет переведена в статус UP.
Переопределить метод EventPublishingRunListener#ready нет возможности, поэтому было решено при старте запускать формирование отчета в новом потоке. Т.к. продолжительный метод генерации выполняется в новом потоке, в основном потоке метод generateAtStartup быстро завершается, не блокируясь, и readiness probe переводится в UP.

@Autowired
ScheduledExecutorService executorService;

@EventListener(ApplicationReadyEvent.class)
public void generateAtStartup() {
executorService.schedule(this::generateReport, 20, TimeUnit.SECONDS);
}

private void generate() { //логика создания отчета }

#рабочее
  • 😁 1
More from @system_design_explained
  1. Sep 22, 2026Нашла способ, который мгновенно и без дополнительных усилий увеличил мою продуктивность пр…
  2. Mar 27, 2026Я в ВК : https://vk.ru/dev_with_dm
  3. Mar 27, 2026Читаю в последнее время много критики микросервисов, и у меня тоже есть пример, как раз за…
  4. Mar 4, 2026В функциональных языках рекомендуется делать все объекты immutable, и, хотя на работе я пи…
  5. Dec 4, 2025Недавно занималась задачей, где нужно было реализовать оптимистическую блокировку сущности…
  6. Nov 21, 2025Обнаружила еще один плюс TDD. Согласно подходу, я пишу тест, который падает, пишу код, что…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →