com.ibm.cp4waiops.connectors.sdk.GRPCCloudEventConfigurationChannel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of connectors-sdk Show documentation
Show all versions of connectors-sdk Show documentation
A developer SDK for creating connectors for CP4WAIOps.
The newest version!
package com.ibm.cp4waiops.connectors.sdk;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.ibm.aiops.connectors.bridge.ConnectorBridgeGrpc.ConnectorBridgeStub;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
/**
* Consumes cloud events from the target channel
*/
class GRPCCloudEventConfigurationChannel implements StreamObserver, AutoCloseable {
private static final Logger logger = Logger.getLogger(GRPCCloudEventConfigurationChannel.class.getName());
private String _name;
private ConnectorBridgeStub _stub;
private CloudEvent _template;
AtomicReference _output;
private AtomicBoolean _streamActive;
private AtomicBoolean _shouldClose;
private Counter _consumedCount;
private Counter _droppedCount;
private Counter _streamStartCount;
/**
* Constructs an instance
*
* @param channelName
* the name of the channel that will be sent to the server, most likely the name of the kafka topic
* @param stub
* the interface used to communicate with the bridge server
* @param requestTemplate
* the template used for the request that initializes the channel
* @param output
* a queue where incoming cloud events will be placed
* @param meterRegistry
* a registry for recording channel metrics
*/
GRPCCloudEventConfigurationChannel(String channelName, ConnectorBridgeStub stub, CloudEvent requestTemplate,
AtomicReference latestReceivedConfiguration, MeterRegistry meterRegistry,
Counter configStartCounter) {
_name = channelName;
_stub = stub;
_template = requestTemplate;
_output = latestReceivedConfiguration;
_streamActive = new AtomicBoolean(false);
_shouldClose = new AtomicBoolean(false);
_consumedCount = meterRegistry.counter("connector.sdk.config.received", Constant.CHANNEL_NAME_TAG, channelName);
_droppedCount = meterRegistry.counter("connector.sdk.config.dropped", Constant.CHANNEL_NAME_TAG, channelName);
_streamStartCount = configStartCounter;
}
double getConsumedCount() {
return _consumedCount.count();
}
double getDroppedCount() {
return _droppedCount.count();
}
double getStreamRestartCount() {
return _streamStartCount.count() - 1;
}
/**
* Starts the configuration channel
*/
void startConfigrationChannel() {
// Ignore if already active
if (_streamActive.get()) {
logger.log(Level.FINE, "Stream is active" + _name);
return;
}
// setup stream
logger.log(Level.INFO, "starting configuration consume stream: channel=" + _name);
_streamStartCount.increment();
CloudEvent request = CloudEventBuilder.from(_template).withId(UUID.randomUUID().toString())
.withExtension(Connector.REQUEST_ID_CE_EXTENSION_NAME, UUID.randomUUID().toString()).build();
io.cloudevents.v1.proto.CloudEvent convertedRequest;
try {
convertedRequest = Util.convertCloudEventToProto(request);
} catch (Exception error) {
logger.log(Level.SEVERE, "failed to convert request, consume stream will not start: name=" + _name, error);
return;
}
_stub.configuration(convertedRequest, this);
}
/**
* Restarts the consume channel if it is inactive
*/
void fixChannelIfStopped() {
startConfigrationChannel();
}
/**
* Asynchronously stops the consume channel
*/
@Override
public void close() {
logger.log(Level.INFO, "stopping consume stream: channel=" + _name);
_streamActive.set(false);
_shouldClose.set(true);
}
@Override
public void onNext(io.cloudevents.v1.proto.CloudEvent proto) {
// Close stream if requested
if (_shouldClose.get()) {
_streamActive.set(false);
throw Status.CANCELLED.asRuntimeException();
}
// Convert
CloudEvent event;
try {
event = Util.convertCloudEventFromProto(proto);
_streamActive.set(true);
} catch (Exception error) {
logger.log(Level.SEVERE, "proto to cloud event conversion failed, dropping: id=" + proto.getId());
_droppedCount.increment();
return;
}
// Log
if (logger.isLoggable(Level.FINE)) {
try {
logger.log(Level.FINE,
"receiving cloud event: channel=" + _name + ",event=" + Util.convertCloudEventToJSON(event));
} catch (Exception error) {
logger.log(Level.FINE, "failed to serialize event for logging", error);
}
}
try {
_output.set(event);
_consumedCount.increment();
} catch (Exception error) {
logger.log(Level.WARNING, "onNext() interrupted, event will be dropped: _channel=" + _name, error);
Thread.currentThread().interrupt();
}
}
@Override
public void onError(Throwable t) {
logger.log(Level.WARNING, "consume stream terminated with an error: channel=" + _name, t);
String improvedDiagnostic = Util.getDiagnosticMessage(t);
if (improvedDiagnostic != null) {
logger.log(Level.WARNING, improvedDiagnostic);
}
_streamActive.set(false);
}
@Override
public void onCompleted() {
logger.log(Level.INFO, "consume stream terminated cleanly: channel=" + _name);
_streamActive.set(false);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy