-
Notifications
You must be signed in to change notification settings - Fork 41.2k
Add Cassandra health indicator that uses CqlSession #20887
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Row row = this.session.execute(SELECT).one(); | ||
Assert.notNull(row, "system.local should always return one row"); | ||
String version = row.getString(0); | ||
Assert.notNull(version, "release_version should never be null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These assertions really will never fail as any C* node would report exactly one row with one non-null column for such a CQL query. But they make static analysis tools happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to do that, you could check if the row is non null (since the API forces you to do that check), something like:
Row row = this.session.execute(SELECT).one();
builder.up();
if (row != null) {
builder.withDetail("version", row.getString(0));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't that slightly different? In the very unlikely case where the row would be null, in my version the health indicator would be set to DOWN, whereas in your case, it would be UP. But I will do as you suggest, since a null row is totally unrealistic anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right, I overlooked that. Although the "These assertions really will never fail" makes me think it won't make a difference.
return this.reactiveCassandraOperations.getReactiveCqlOperations().queryForObject(SELECT, String.class) | ||
.map((version) -> builder.up().withDetail("version", version).build()).single(); | ||
return Mono.from(this.session.executeReactive(SELECT)) | ||
.map((row) -> Objects.requireNonNull(row.getString(0), "release_version should never be null")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, Objects.requireNonNull
is just making my IDE happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IntelliJ IDEA? I think that's a false positive.
return Mono.from(this.session.executeReactive(SELECT))
.map((row) -> builder.up().withDetail("version", row.getString(0)).build());
this is more concise and doesn't yield any warning for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually GettableByIndex#getString(int)
is marked @Nullable
in the driver API, so it may trigger a warning depending on how you configure things. But again I don't mind really, I'll do as you suggest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's going a tad too far. The row
will never be null
given the contract of Publisher
and onNext
.
@@ -38,25 +39,24 @@ | |||
private static final SimpleStatement SELECT = SimpleStatement | |||
.newInstance("SELECT release_version FROM system.local").setConsistencyLevel(ConsistencyLevel.LOCAL_ONE); | |||
|
|||
private CassandraOperations cassandraOperations; | |||
|
|||
public CassandraHealthIndicator() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed because it doesn't buy us anything, but this is a breaking change. Let me know if you prefer to keep it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR. I've replied to your 2 comments.
Mocking Publisher
is going a step too far I think and I am not sure I want to start a Cassandra instance for such a test. I don't know if there is an alternative.
CassandraHealthIndicator healthIndicator = new CassandraHealthIndicator(cassandraOperations); | ||
CqlSession session = mock(CqlSession.class); | ||
given(session.execute(any(SimpleStatement.class))) | ||
.willThrow(new DriverTimeoutException("Connection timed out (not really)")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change that to Test Exception
if you want to make it clear it's a test exception.
}).verifyComplete(); | ||
} | ||
|
||
private Answer<Void> mockReactiveResultSetBehavior(ReactiveRow row) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh. I am not keen to start mocking a Publisher
here. The fact that the return type is a Publisher
+ something else makes it very hard to use existing reactor types. WIthout that I could have replaced that with Mono.just
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't see how to simplify this either. I'll take a note to provide a dummy implementation of ReactiveResultSet
for test use cases like this one, in a future driver release.
@@ -39,7 +41,7 @@ | |||
* @see EnableReactiveCassandraRepositories | |||
*/ | |||
@Configuration(proxyBeanMethods = false) | |||
@ConditionalOnClass({ ReactiveSession.class, ReactiveCassandraRepository.class }) | |||
@ConditionalOnClass({ ReactiveSession.class, ReactiveCassandraRepository.class, Flux.class }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not against that change but it has nothing to do with the task at hand. Please revert that and submit it in a separate change if you think this is worth exploring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, this is a mistake, I will remove.
We don't want to break backward compatible for this one. This should be possible by keeping the existing health indicator, adding this one and updating the auto-configuration to try this one and then the existing one if none apply. Unfortunately, the existing health indicator is in the It is unfortunately too late to make a breaking change in |
I understand your concerns. I will rework this PR in the way you suggested, and should have something ready shortly. If you don't mind, since we are back to square zero anyway, I will rebase on master and squash the commits. |
What do you suggest for class names? I'm currently planning on declaring all health indicators under
Is that ok? |
Motivation: It is possible to use CassandraAutoConfiguration to create CqlSession beans in an application with just a dependency on the DataStax Java driver, without the requirement to also depend on Spring Data Cassandra. However, it is currently not possible to do so if the application also needs to create Actuator components. Indeed, both CassandraHealthIndicator and CassandraReactiveHealthIndicator have a hard dependency on Spring Data Cassandra and its CassandraOperations bean. Modifications: This commit creates two new health indicators that do not have any dependency on Spring Data Cassandra: CassandraDriverHealthIndicator and CassandraDriverReactiveHealthIndicator; these indicators are automatically used in lieu of CassandraHealthIndicator and CassandraReactiveHealthIndicator when Spring Data Cassandra is not available. Result: Users are now able to create Actuator health components in their applications, even if they use just Spring Boot and the DataStax Java driver, without Spring Data Cassandra.
@adutra Those names sound sensible to me. We can always refine them if we think of something better when we merge. |
This commit provides a CassandraDriverHealthIndicator and CassandraDriverReactiveHealthIndicator that do not require Spring Data. As a result, a health indicator for Cassandra is provided even if the application does not use Spring Data. See gh-20887
Thanks @adutra. I've merged your contribution with a polish commit. |
For the record, we've decided to deprecate the health indicators that rely on Spring Data (see #23226). |
Motivation:
It is possible to use CassandraAutoConfiguration to create CqlSession
beans in an application with just a dependency on the DataStax Java driver,
without the requirement to also depend on Spring Data Cassandra.
However, it is currently not possible to do so if the application also
needs to create Actuator components. Indeed, both CassandraHealthIndicator
and CassandraReactiveHealthContributorAutoConfiguration have a hard
dependency on Spring Data Cassandra and its CassandraOperations bean.
Modifications:
This commit removes the hard dependency on Spring Data Cassandra from
CassandraHealthIndicator and CassandraReactiveHealthContributorAutoConfiguration,
and replaces all usages of CassandraOperations with direct access to the
underlying CqlSession bean.
Result:
Users are now able to create Actuator health components in their applications,
even if they use just Spring Boot and the DataStax Java driver, without
Spring Data Cassandra.