Статьи

Grails Goodness: добавление показателей проверки работоспособности

С Grails 3 мы также получаем привод Spring Boot . Мы можем использовать Spring Boot Actuator, чтобы добавить некоторые готовые к работе функции для мониторинга и управления нашим приложением Grails. Одной из функций является добавление некоторых конечных точек с информацией о нашем приложении. По умолчанию у нас уже есть конечная точка /health когда мы запускаем приложение Grails (3+). Он возвращает ответ JSON со статусом UP . Давайте расширим эту конечную точку и добавим индикатор места на диске, базы данных и проверки работоспособности URL.

Мы можем установить для свойства приложения endpoints.health.sensitive значение false (защита этих конечных точек будет другой публикацией в блоге), и мы автоматически получим индикатор работоспособности дискового пространства. Пороговое значение по умолчанию установлено на 10 МБ, поэтому, когда дисковое пространство меньше 10 МБ, состояние устанавливается на ВНИЗ . В следующем фрагменте показано изменение в grails-app/conf/application.yml для установки свойства:

1
2
3
4
5
6
...
---
endpoints:
    health:
        sensitive: false
...

Если мы вызовем конечную точку /health мы получим следующий вывод:

1
2
3
4
5
6
7
8
{
    "status": "UP",
    "diskSpace": {
        "status": "UP",
        "free": 97169154048,
        "threshold": 10485760
    }
}

Если мы хотим изменить threshold мы можем создать bean-компонент Spring типа DiskSpaceHealthIndicatorProperties и назвать diskSpaceHealthIndicatorProperties чтобы переопределить бин по умолчанию. Начиная с Grails 3, мы можем переопределить метод doWithSpring в классе Application для определения doWithSpring Spring:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package healthcheck
 
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties
 
class Application extends GrailsAutoConfiguration {
 
    static void main(String[] args) {
        GrailsApp.run(Application)
    }
 
    @Override
    Closure doWithSpring() {
        { ->
            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                // Set threshold to 250MB.
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

Spring Boot Actuator уже содержит реализации для проверки баз данных SQL, Mongo, Redis, Solr и RabbitMQ. Мы можем активировать их, когда добавляем их в виде Spring-компонентов в контекст нашего приложения. Затем они автоматически выбираются и добавляются к результатам конечной точки /health . В следующем примере мы создаем объект bean-компонента DataSourceHealthIndicator типа DataSourceHealthIndicator :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package healthcheck
 
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DataSourceHealthIndicator
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties
 
class Application extends GrailsAutoConfiguration {
 
    static void main(String[] args) {
        GrailsApp.run(Application)
    }
 
    @Override
    Closure doWithSpring() {
        { ->
            // Configure data source health indicator based
            // on the dataSource in the application context.
            databaseHealthCheck(DataSourceHealthIndicator, dataSource)
 
            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

Чтобы создать собственный класс индикатора работоспособности, мы должны реализовать интерфейс HealthIndicator . Самый простой способ — расширить класс AbstractHealthIndicator и переопределить метод doHealthCheck . Было бы неплохо иметь индикатор работоспособности, который может проверять, доступен ли URL. Например, если нам нужно получить доступ к API REST, доступному через HTTP в нашем приложении, мы можем проверить, доступен ли он.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package healthcheck
 
import org.springframework.boot.actuate.health.AbstractHealthIndicator
import org.springframework.boot.actuate.health.Health
 
class UrlHealthIndicator extends AbstractHealthIndicator {
 
    private final String url
 
    private final int timeout
 
    UrlHealthIndicator(final String url, final int timeout = 10 * 1000) {
        this.url = url
        this.timeout = timeout
    }
 
    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        final HttpURLConnection urlConnection =
                (HttpURLConnection) url.toURL().openConnection()
 
        final int responseCode =
                urlConnection.with {
                    requestMethod = 'HEAD'
                    readTimeout = timeout
                    connectTimeout = timeout
                    connect()
                    responseCode
                }
 
        // If code in 200 to 399 range everything is fine.
        responseCode in (200..399) ?
                builder.up() :
                builder.down(
                        new Exception(
                                "Invalid responseCode '${responseCode}' checking '${url}'."))
    }
}

В нашем классе Application мы создаем bean-компонент Spring для этого индикатора работоспособности, чтобы он принимался кодом Spring Boot Actuator:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package healthcheck
 
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DataSourceHealthIndicator
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties
 
class Application extends GrailsAutoConfiguration {
 
    static void main(String[] args) {
        GrailsApp.run(Application)
    }
 
    @Override
    Closure doWithSpring() {
        { ->
            // Create instance for URL health indicator.
            urlHealthCheck(UrlHealthIndicator, 'http://intranet', 2000)
 
            databaseHealthCheck(DataSourceHealthIndicator, dataSource)
 
            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

Теперь, когда мы запускаем наше приложение Grails и получаем доступ к конечной точке /health мы получаем следующий JSON:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
{
    "status": "DOWN",
    "urlHealthCheck": {
        "status": "DOWN"
        "error": "java.net.UnknownHostException: intranet",
    },
    "databaseHealthCheck": {
        "status": "UP"
        "database": "H2",
        "hello": 1,
    },
    "diskSpace": {
        "status": "UP",
        "free": 96622411776,
        "threshold": 262144000
    },
}

Обратите внимание, что проверка работоспособности URL не удалась, поэтому для полного состояния установлено значение ВНИЗ .

Написано с Grails 3.0.1.