Skip to content
This repository was archived by the owner on Sep 1, 2023. It is now read-only.

Commit f52303d

Browse files
GH-18 - Include the edition of the database in the health endpoint.
1 parent f657b2f commit f52303d

File tree

6 files changed

+88
-16
lines changed

6 files changed

+88
-16
lines changed

neo4j-java-driver-spring-boot-autoconfigure/src/main/java/org/neo4j/driver/springframework/boot/actuate/Neo4jHealthIndicator.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.commons.logging.LogFactory;
2323
import org.neo4j.driver.AccessMode;
2424
import org.neo4j.driver.Driver;
25+
import org.neo4j.driver.Result;
2526
import org.neo4j.driver.Session;
2627
import org.neo4j.driver.exceptions.SessionExpiredException;
2728
import org.neo4j.driver.SessionConfig;
@@ -47,7 +48,7 @@ public final class Neo4jHealthIndicator extends AbstractHealthIndicator {
4748
/**
4849
* The Cypher statement used to verify Neo4j is up.
4950
*/
50-
static final String CYPHER = "RETURN 1 AS result";
51+
static final String CYPHER = "CALL dbms.components() YIELD name, edition WHERE name = 'Neo4j Kernel' RETURN edition";
5152
/**
5253
* Message indicating that the health check failed.
5354
*/
@@ -75,15 +76,15 @@ public Neo4jHealthIndicator(Driver driver) {
7576
protected void doHealthCheck(Health.Builder builder) {
7677

7778
try {
78-
ResultSummary resultSummary;
79+
ResultSummaryWithEdition resultSummaryWithEdition;
7980
// Retry one time when the session has been expired
8081
try {
81-
resultSummary = runHealthCheckQuery();
82+
resultSummaryWithEdition = runHealthCheckQuery();
8283
} catch (SessionExpiredException sessionExpiredException) {
8384
logger.warn(MESSAGE_SESSION_EXPIRED);
84-
resultSummary = runHealthCheckQuery();
85+
resultSummaryWithEdition = runHealthCheckQuery();
8586
}
86-
buildStatusUp(resultSummary, builder);
87+
buildStatusUp(resultSummaryWithEdition, builder);
8788
} catch (Exception ex) {
8889
builder.down().withException(ex);
8990
}
@@ -92,15 +93,17 @@ protected void doHealthCheck(Health.Builder builder) {
9293
/**
9394
* Applies the given {@link ResultSummary} to the {@link Health.Builder builder} without actually calling {@code build}.
9495
*
95-
* @param resultSummary the result summary returned by the server
96+
* @param resultSummaryWithEdition the result summary returned by the server
9697
* @param builder the health builder to be modified
9798
* @return the modified health builder
9899
*/
99-
static Health.Builder buildStatusUp(ResultSummary resultSummary, Health.Builder builder) {
100-
ServerInfo serverInfo = resultSummary.server();
101-
DatabaseInfo databaseInfo = resultSummary.database();
100+
static Health.Builder buildStatusUp(ResultSummaryWithEdition resultSummaryWithEdition, Health.Builder builder) {
101+
ServerInfo serverInfo = resultSummaryWithEdition.resultSummary.server();
102+
DatabaseInfo databaseInfo = resultSummaryWithEdition.resultSummary.database();
102103

103-
builder.up().withDetail("server", serverInfo.version() + "@" + serverInfo.address());
104+
builder.up()
105+
.withDetail("server", serverInfo.version() + "@" + serverInfo.address())
106+
.withDetail("edition", resultSummaryWithEdition.edition);
104107

105108
if (StringUtils.hasText(databaseInfo.name())) {
106109
builder.withDetail("database", databaseInfo.name());
@@ -109,12 +112,14 @@ static Health.Builder buildStatusUp(ResultSummary resultSummary, Health.Builder
109112
return builder;
110113
}
111114

112-
ResultSummary runHealthCheckQuery() {
115+
ResultSummaryWithEdition runHealthCheckQuery() {
113116
// We use WRITE here to make sure UP is returned for a server that supports
114117
// all possible workloads
115118
try (Session session = this.driver.session(DEFAULT_SESSION_CONFIG)) {
116-
ResultSummary resultSummary = session.run(CYPHER).consume();
117-
return resultSummary;
119+
Result result = session.run(CYPHER);
120+
String edition = result.single().get("edition").asString();
121+
ResultSummary resultSummary = result.consume();
122+
return new ResultSummaryWithEdition(resultSummary, edition);
118123
}
119124
}
120125
}

neo4j-java-driver-spring-boot-autoconfigure/src/main/java/org/neo4j/driver/springframework/boot/actuate/Neo4jReactiveHealthIndicator.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
import org.apache.commons.logging.LogFactory;
2727
import org.neo4j.driver.Driver;
2828
import org.neo4j.driver.exceptions.SessionExpiredException;
29+
import org.neo4j.driver.reactive.RxResult;
2930
import org.neo4j.driver.reactive.RxSession;
30-
import org.neo4j.driver.summary.ResultSummary;
3131
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
3232
import org.springframework.boot.actuate.health.Health;
3333
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
@@ -60,12 +60,16 @@ protected Mono<Health> doHealthCheck(Health.Builder builder) {
6060
.map(r -> buildStatusUp(r, builder).build());
6161
}
6262

63-
Mono<ResultSummary> runHealthCheckQuery() {
63+
Mono<ResultSummaryWithEdition> runHealthCheckQuery() {
6464
// We use WRITE here to make sure UP is returned for a server that supports
6565
// all possible workloads
6666
return Mono.using(
6767
() -> this.driver.rxSession(DEFAULT_SESSION_CONFIG),
68-
session -> Mono.from(session.run(Neo4jHealthIndicator.CYPHER).consume()),
68+
session -> {
69+
RxResult result = session.run(Neo4jHealthIndicator.CYPHER);
70+
return Mono.from(result.records()).map(record -> record.get("edition").asString())
71+
.zipWhen(edition -> Mono.from(result.consume()), (e, r) -> new ResultSummaryWithEdition(r, e));
72+
},
6973
RxSession::close
7074
);
7175
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2019-2020 "Neo4j,"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* https://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver.springframework.boot.actuate;
20+
21+
import org.neo4j.driver.summary.ResultSummary;
22+
23+
/**
24+
* A holder for a {@link ResultSummary result summary} and database edition.
25+
*
26+
* @author Michael J. Simons
27+
* @soundtrack Black Sabbath - The End
28+
* @since 4.0.0.2
29+
*/
30+
final class ResultSummaryWithEdition {
31+
32+
final ResultSummary resultSummary;
33+
34+
final String edition;
35+
36+
ResultSummaryWithEdition(ResultSummary resultSummary, String edition) {
37+
this.resultSummary = resultSummary;
38+
this.edition = edition;
39+
}
40+
41+
42+
}

neo4j-java-driver-spring-boot-autoconfigure/src/test/java/org/neo4j/driver/springframework/boot/actuate/Neo4jHealthIndicatorTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.mockito.junit.jupiter.MockitoExtension;
3030
import org.neo4j.driver.Result;
3131
import org.neo4j.driver.Session;
32+
import org.neo4j.driver.Values;
3233
import org.neo4j.driver.exceptions.ServiceUnavailableException;
3334
import org.neo4j.driver.exceptions.SessionExpiredException;
3435
import org.neo4j.driver.SessionConfig;
@@ -56,6 +57,8 @@ void shouldWorkWithoutDatabaseName() {
5657

5758
when(this.databaseInfo.name()).thenReturn(null);
5859

60+
when(record.get("edition")).thenReturn(Values.value("some edition"));
61+
when(this.statementResult.single()).thenReturn(this.record);
5962
when(this.statementResult.consume()).thenReturn(this.resultSummary);
6063
when(this.session.run(anyString())).thenReturn(this.statementResult);
6164

@@ -66,6 +69,7 @@ void shouldWorkWithoutDatabaseName() {
6669
assertThat(health.getStatus()).isEqualTo(Status.UP);
6770
assertThat(health.getDetails()).containsEntry("server", "4711@Zu Hause");
6871
assertThat(health.getDetails()).doesNotContainKey("database");
72+
assertThat(health.getDetails()).containsEntry("edition", "some edition");
6973
}
7074

7175
@Test
@@ -77,6 +81,8 @@ void shouldWorkWithEmptyDatabaseName() {
7781

7882
when(this.databaseInfo.name()).thenReturn("");
7983

84+
when(record.get("edition")).thenReturn(Values.value("some edition"));
85+
when(this.statementResult.single()).thenReturn(this.record);
8086
when(this.statementResult.consume()).thenReturn(this.resultSummary);
8187
when(this.session.run(anyString())).thenReturn(this.statementResult);
8288

@@ -87,12 +93,15 @@ void shouldWorkWithEmptyDatabaseName() {
8793
assertThat(health.getStatus()).isEqualTo(Status.UP);
8894
assertThat(health.getDetails()).containsEntry("server", "4711@Zu Hause");
8995
assertThat(health.getDetails()).doesNotContainKey("database");
96+
assertThat(health.getDetails()).containsEntry("edition", "some edition");
9097
}
9198

9299
@Test
93100
void neo4jIsUp() {
94101

95102
prepareSharedMocks();
103+
104+
when(this.statementResult.single()).thenReturn(this.record);
96105
when(this.statementResult.consume()).thenReturn(this.resultSummary);
97106
when(this.session.run(anyString())).thenReturn(this.statementResult);
98107

@@ -103,6 +112,7 @@ void neo4jIsUp() {
103112
assertThat(health.getStatus()).isEqualTo(Status.UP);
104113
assertThat(health.getDetails()).containsEntry("server", "4711@Zu Hause");
105114
assertThat(health.getDetails()).containsEntry("database", "n/a");
115+
assertThat(health.getDetails()).containsEntry("edition", "ultimate collectors edition");
106116

107117
verify(session).close();
108118
verifyNoMoreInteractions(this.driver, this.session, this.statementResult, this.resultSummary, this.serverInfo, this.databaseInfo);
@@ -114,6 +124,7 @@ void neo4jSessionIsExpiredOnce() {
114124
AtomicInteger cnt = new AtomicInteger(0);
115125

116126
prepareSharedMocks();
127+
when(this.statementResult.single()).thenReturn(this.record);
117128
when(this.statementResult.consume()).thenReturn(this.resultSummary);
118129
when(this.session.run(anyString())).thenAnswer(invocation -> {
119130
if (cnt.compareAndSet(0, 1)) {

neo4j-java-driver-spring-boot-autoconfigure/src/test/java/org/neo4j/driver/springframework/boot/actuate/Neo4jHealthIndicatorTestBase.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import org.mockito.Mock;
2424
import org.neo4j.driver.Driver;
25+
import org.neo4j.driver.Record;
26+
import org.neo4j.driver.Values;
2527
import org.neo4j.driver.summary.DatabaseInfo;
2628
import org.neo4j.driver.summary.ResultSummary;
2729
import org.neo4j.driver.summary.ServerInfo;
@@ -45,12 +47,16 @@ abstract class Neo4jHealthIndicatorTestBase {
4547
@Mock
4648
protected DatabaseInfo databaseInfo;
4749

50+
@Mock
51+
protected Record record;
52+
4853
protected void prepareSharedMocks() {
4954

5055
when(serverInfo.version()).thenReturn("4711");
5156
when(serverInfo.address()).thenReturn("Zu Hause");
5257
when(databaseInfo.name()).thenReturn("n/a");
5358
when(resultSummary.server()).thenReturn(serverInfo);
5459
when(resultSummary.database()).thenReturn(databaseInfo);
60+
when(record.get("edition")).thenReturn(Values.value("ultimate collectors edition"));
5561
}
5662
}

neo4j-java-driver-spring-boot-autoconfigure/src/test/java/org/neo4j/driver/springframework/boot/actuate/Neo4jReactiveHealthIndicatorTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class Neo4jReactiveHealthIndicatorTest extends Neo4jHealthIndicatorTestBase {
5353
void neo4jIsUp() {
5454

5555
prepareSharedMocks();
56+
when(statementResult.records()).thenReturn(Mono.just(record));
5657
when(statementResult.consume()).thenReturn(Mono.just(resultSummary));
5758
when(session.run(anyString())).thenReturn(statementResult);
5859

@@ -65,6 +66,7 @@ void neo4jIsUp() {
6566
.consumeNextWith(health -> {
6667
assertThat(health.getStatus()).isEqualTo(Status.UP);
6768
assertThat(health.getDetails()).containsEntry("server", "4711@Zu Hause");
69+
assertThat(health.getDetails()).containsEntry("edition", "ultimate collectors edition");
6870
})
6971
.verifyComplete();
7072

@@ -78,6 +80,7 @@ void neo4jSessionIsExpiredOnce() {
7880
AtomicInteger cnt = new AtomicInteger(0);
7981

8082
prepareSharedMocks();
83+
when(statementResult.records()).thenReturn(Mono.just(record));
8184
when(statementResult.consume()).thenReturn(Mono.just(resultSummary));
8285
when(session.run(anyString())).thenAnswer(invocation -> {
8386
if (cnt.compareAndSet(0, 1)) {
@@ -94,6 +97,7 @@ void neo4jSessionIsExpiredOnce() {
9497
.consumeNextWith(health -> {
9598
assertThat(health.getStatus()).isEqualTo(Status.UP);
9699
assertThat(health.getDetails()).containsEntry("server", "4711@Zu Hause");
100+
assertThat(health.getDetails()).containsEntry("edition", "ultimate collectors edition");
97101
})
98102
.verifyComplete();
99103

0 commit comments

Comments
 (0)