How to implement custom actuator endpoint to check zookeeper health? - apache-zookeeper

I would like to implement a custom endpoint class to check Zookeeper health:
http://localhost:8080/actuator/health/zookeeper
PROBLEM: Do I extend AbstractHealthIndicaitor or implement HealthIndicator class?
HealthIndicator class
public class CustomHealth implements HealthIndicator {
#Override
public Health health() {
int errorCode = check(); // perform some specific health check
if (errorCode != 0) {
return Health.down()
.withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
public int check() {
// Our logic to check zookeeper health
return 0;
}
}
AbstractHealthIndicator class
public class CustomHealth extends AbstractHealthIndicator {
#Override
protected void doHealthCheck(Health.Builder builder) throws Exception
{
// Our logic to check zookeeper health
}
}
I'm confused on which approach to use. I believe the logic to check zookeeper health is to simply declare an CuratorFramework object then do curator.getState() and return builder from there and for endpoint, attach #RestControllerEndPoint to declare the path. Please help!

It is up to you which one to choose, the difference is that AbstractHealthIndicator:
Provides you with the Health.Builder instance so you don't need to create one manually
Wraps doHealthCheck(builder) call with try-catch, that returns status DOWN if your healthcheck has failed with exception.
So in general the AbstractHealthIndicator is more convenient to use as you can skip error handling. Choose implementing raw HealthIndicator when you need to provide custom status details on exception.
For example of Zookeeper Health Indicator please refer to existing one provided with spring-cloud-zookeeper https://github.com/spring-cloud/spring-cloud-zookeeper/blob/master/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperHealthIndicator.java
Regarding the endpoint /actuator/health/zookeeper, I suggest you to use new feature introduced in SpringBoot 2.2.0 called Health Indicator Groups https://spring.io/blog/2019/10/16/spring-boot-2-2-0#health-indicator-groups
In short, if you use component scan and named custom health indicator MyZookeeperHealthIndicator, then add following properties to register it under custom zookeeper group:
management.endpoint.health.group.zookeeper.include=myZookeeper
After that, custom health details will be displayed under myZookeeper component at /actuator/health/zookeeper
Check following docs for more information:
Writing Custom HealthIndicators https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#writing-custom-healthindicators
Health Groups https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#health-groups

Related

Design of a pipeline that invokes a maximum number of requests per second

My goal is to create a pipeline that invokes a back-end (Cloud hosted) service a maximum number of times per second ... how can I achieve that?
Back story: Imagine a back-end service that is invoked with a single input and returns a single output. This service has quotas associated with it that permit a maximum number of requests per second (let's say 10 requests per second). Now imagine an unbounded source PCollection where I wish to transform the elements in the input by passing them through my back-end service. I can envisage a ParDo invoking the back-end service once for each element in the input PCollection. However, this doesn't perform any kind of flow control against the back-end.
I could imagine my DoFn logic testing the response from the back-end response and retrying till it succeeds but this doesn't feel right. If I have 100 workers, then I seem to be burning a lot of resources and putting a load on the back-end. What I think I want to do is throttle the calls to the back-end from the pipeline.
Good Day, kolban. In addition to Bruno Volpato's helpful RampupThrottlingFn example, I've seen a combination of the following. Please do not hesitate at all to let me know how I can update the example with more clarity.
PeriodicImpulse - emits an Instant at a fixed specified interval.
Fix the number of workers with the maxNumWorkers and numWorkers (Please see Dataflow Pipeline Options), if using the Dataflow runner.
Beam Metrics API to monitor the actual resource request count over time and set alerts. When using Dataflow, the Beam Metrics API automatically connects to Cloud Monitoring as Custom metrics
The following shows abbreviated code starting from the whole pipeline followed by some details as needed to provide clarity. It assumes a target of 10 workers, using Dataflow with the arguments --maxNumWorkers=10 and --numWorkers=10 and a goal to limit the resource requests among all workers to 10 requests per second. This translates to 1 request per second per worker.
PeriodicImpulse limits the Request creation to 1 per second
public class MyPipeline {
public static void main(String[] args) {
Pipeline pipeline = Pipeline.create(/* Usually with options */);
PCollection<Response> responses = pipeline.apply(
"PeriodicImpulse",
PeriodicImpulse
.create()
.withInterval(Duration.standardSeconds(1L))
).apply(
"Build Requests",
ParDo.of(new RequestFn())
)
.apply(ResourceTransform.create());
}
}
RequestFn DoFn emits Requests per Instant emitted from PeriodicImpulse
class RequestFn extends DoFn<Instant, Request> {
#ProcessElement
public void process(#Element Instant instant, OutputReceiver<Request> receiver) {
receiver.output(
Request.builder().build()
);
}
}
ResourceTransform transforms Requests to Responses, incrementing a Counter
class ResourceTransform extends PTransform<PCollection<Request>, PCollection<Response>> {
static ResourceTransform create() {
return new ResourceTransform();
}
public PCollection<Response> expand(PCollection<Request> input) {
return ParDo.of("Consume Resource", new ResourceFn());
}
}
class ResourceFn extends DoFn<Request, Response> {
private Counter counter = Metrics.counter(ResourceFn.class, "some:resource");
private transient ResourceClient client = null;
#Setup
public void setup() {
client = new ResourceClient();
}
#ProcessElement
public void process(#Element Request request, OutputReceiver<> receiver)
{
counter.inc(); // Increment the counter.
// not showing error handling
Response response = client.execute(request);
receiver.output(response);
}
}
Request and Response classes
(Aside: consider creating a Schema for the request input and response output classes. Example below uses AutoValue and AutoValueSchema)
#DefaultSchema(AutoValueSchema.class)
#AutoValue
abstract class Request {
/* abstract Getters. */
abstract String getId();
#AutoValue.Builder
static abstract class Builder {
/* abstract Setters. */
abstract Builder setId(String value);
abstract Request build();
}
}
#DefaultSchema(AutoValueSchema.class)
#AutoValue
abstract class Response {
/* abstract Getters. */
abstract String getId();
#AutoValue.Builder
static abstract class Builder {
/* abstract Setters. */
abstract Builder setId(String value);
abstract Response build();
}
}

Dropwizard Rest Application. How to view only my custom metrics

Hello Rest Api lovers !!
I created a DropWizard basic rest application.
I would like to view metrics but ONLY MY CUSTOM ONES and not dropwizard api's.
how can i disable dropwizard's healtCheks and Metrics and only view mines (the custum ones).
I hope it is clear....
If you are concerned about the "view" part of metrics/healthchecks, you can set filter that will apply when data is returned. It can be done on start of an application:
environment.getAdminContext().setAttribute(MetricsServlet.METRIC_FILTER, new MetricFilter() {
#Override
public boolean matches(final String name, final Metric metric) {
return // you logic;
}
});
environment.getAdminContext().setAttribute(HealthCheckServlet.HEALTH_CHECK_FILTER, new HealthCheckFilter() {
#Override
public boolean matches(final String s, final HealthCheck healthCheck) {
return // you logic;
}
});
If you don't want to have metrics/healthchecks at all, you can directly remove them:
environment.healthChecks().unregister();
environment.metrics().remove();

Health check on Spring Boot webapp from another Spring Boot webapp

I currently have a Spring Boot app where I can access the health check via actuator.
This app is dependent on another Spring Boot App being available/up so my question is:
By overriding the health check in the first app, is there an elegant way to do a health check on the second app?
In essence I just want to use one call and get health-check-info for both applications.
You can develop an own health indicator by implementing HealthIndicator that checks the health of the backend app. So in essence that will not be too difficult, cause you can just use the RestTemplate you get out of the box, e.g.
public class DownstreamHealthIndicator implements HealthIndicator {
private RestTemplate restTemplate;
private String downStreamUrl;
#Autowired
public DownstreamHealthIndicator(RestTemplate restTemplate, String downStreamUrl) {
this.restTemplate = restTemplate;
this.downStreamUrl = downStreamUrl;
}
#Override
public Health health() {
try {
JsonNode resp = restTemplate.getForObject(downStreamUrl + "/health", JsonNode.class);
if (resp.get("status").asText().equalsIgnoreCase("UP")) {
return Health.up().build();
}
} catch (Exception ex) {
return Health.down(ex).build();
}
return Health.down().build();
}
}
If you have a controller in the App A, then you can introduce a GET method request in the controller and point it to the App B health check API endpoint. In this way, you will have an API endpoint available in App A to check App B's health as well.

Recommended way to register custom serializer with StateManager

In the pre-GA version of Service Fabric I was registering a custom serializer like this:
protected override IReliableStateManager CreateReliableStateManager()
{
IReliableStateManager result = new ReliableStateManager(
new ReliableStateManagerConfiguration(
onInitializeStateSerializersEvent: InitializeStateSerializers));
return result;
}
private Task InitializeStateSerializers()
{
StateManager.TryAddStateSerializer(new KFOBinarySerializer());
return Task.FromResult(false);
}
However, the CreateReliableStateManager method was removed in the GA version. I've struggled to get something working in its place. Currently I'm calling
StateManager.TryAddStateSerializer(new KFOBinarySerializer());
from within the service's RunAsync method, which appears to work fine.
What is the recommended way to register a custom serializer?
TryAddStateSerializer is deprecated. Anyone know if this is because custom serialization support will go away or if it will simply be supported through some other mechanism?
You can create the state manager in the StatefulService's constructor (full example here):
class MyService : StatefulService
{
public MyService(StatefulServiceContext serviceContext)
: base(serviceContext, CreateReliableStateManager()) { }
private static IReliableStateManager CreateReliableStateManager() { ... }
}
Regarding the deprecated API, Microsoft says it's safe to use, but it will change in the future.

Parse HL7 v2.3 REF message with local customizations in HAPI

I am trying parse a HL7 REF I12 message with local customization(NZ).
When I tried using the GenericParser, I keep getting Validation exceptions.
For example for the segment below, I keep get the output
ca.uhn.hl7v2.validation.ValidationException: Validation failed:
Primitive value '(08)569-7555' requires to be empty or a US phone
number
PRD|PP|See T Tan^""^""^^""|""^^^^""^New Zealand||(08)569-7555||14134^NZMC
My question is:
Is there a way to avoid the validation by using the conformance class
generator
Is it possible to create own validation classes using
CustomModelClasses?
In either case, is there any example code for that or tutorial example documentation?
If disabling validation altogether is an option for your application, then you can set the validation context to use NoValidation.
See this thread in the hapi developers mailing list: http://sourceforge.net/p/hl7api/mailman/message/31244500/
Here is an example of how to disable validation:
HapiContext context = new DefaultHapiContext();
context.setValidationContext(new NoValidation());
GenericParser parser = context.getGenericParser();
String message = ...
try {
parser.parse(message);
} catch (Exception e) {
e.printStackTrace();
}
If you still require validation, but just want to change the validator for specific rules, then you'll have to create your own implementation of ValidationContext. This would be done by sub classing ca.uhn.hl7v2.validation.builder.support.NoValidationBuilder and overriding the configure method and use this to instantiate an instance of ValidationContextImpl.
For an example of how to implement the configure method in your subclass of NoValidationBuilder, see the source code for ca.uhn.hl7v2.validation.builder.support.DefaultValidationBuilder. This is the default validation context that is generating the error message you're seeing. To make it easier for you, I'm including the class listing here:
public class DefaultValidationBuilder extends DefaultValidationWithoutTNBuilder {
#Override
protected void configure() {
super.configure();
forAllVersions()
.primitive("TN")
.refersToSection("Version 2.4 Section 2.9.45")
.is(emptyOr(usPhoneNumber()));
}
}
Notice this is the implementation of the usPhoneNumber method defined in BuilderSupport:
public Predicate usPhoneNumber() {
return matches("(\\d{1,2} )?(\\(\\d{3}\\))?\\d{3}-\\d{4}(X\\d{1,5})?(B\\d{1,5})?(C.*)?",
"a US phone number");
}