All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.turbospaces.grpc.consumer.GrpcRequestConsumer Maven / Gradle / Ivy
package com.turbospaces.grpc.consumer;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.Any;
import com.google.protobuf.Message;
import com.turbospaces.api.Topic;
import com.turbospaces.api.TopicRegistry;
import com.turbospaces.api.facade.RequestWrapperFacade;
import com.turbospaces.api.jpa.CompositeStackTracer;
import com.turbospaces.boot.Bootstrap;
import com.turbospaces.cfg.ApplicationConfig;
import com.turbospaces.common.PlatformUtil;
import com.turbospaces.dispatch.AbstractServerRequestConsumer;
import com.turbospaces.dispatch.EmbeddedTransactionalRequest;
import com.turbospaces.dispatch.RequestQueuePostSpec;
import com.turbospaces.dispatch.SafeRequestHandler;
import com.turbospaces.dispatch.TransactionalRequestHandler;
import com.turbospaces.dispatch.TransactionalRequestOutcome;
import com.turbospaces.dispatch.WorkerCompletableTask;
import com.turbospaces.executor.WorkUnit;
import com.turbospaces.grpc.GrpcContextWorkUnit;
import com.turbospaces.grpc.GrpcContextWorkerFactory;
import com.turbospaces.grpc.GrpcHeaders;
import com.turbospaces.mdc.ContextPropagator;
import com.turbospaces.mdc.MdcTags;
import com.turbospaces.rpc.QueuePostTemplate;
import api.v1.ApiFactory;
import io.grpc.stub.StreamObserver;
import io.netty.util.AsciiString;
import io.opentracing.Span;
import jakarta.inject.Inject;
@Service
public class GrpcRequestConsumer extends AbstractServerRequestConsumer {
private final TopicRegistry topicRegistry;
private final Map> handlers;
private GrpcContextWorkerFactory workerFactory;
@Inject
public GrpcRequestConsumer(
TopicRegistry topicRegistry,
QueuePostTemplate> postTemplate,
List> handlers,
GrpcContextWorkerFactory workerFactory,
ApiFactory apiFactory,
CompositeStackTracer stackTracer) {
super(postTemplate, apiFactory, stackTracer);
this.topicRegistry = Objects.requireNonNull(topicRegistry);
this.workerFactory = Objects.requireNonNull(workerFactory);
this.handlers = ImmutableMap.copyOf(handlers.stream().collect(
Collectors.toMap(h -> {
Message defaultInstance = com.google.protobuf.Internal.getDefaultInstance(h.requestType());
Any any = Any.pack(defaultInstance);
return any.getTypeUrl();
}, Function.identity())));
}
public void accept(
REQ req,
Class type,
StreamObserver responseObserver) throws Throwable {
UUID messageId = UUID.fromString(GrpcHeaders.CONTEXT_MESSAGE_ID.get());
GrpcContextWorkUnit unit = GrpcContextWorkUnit.fromCurrentContext();
RequestQueuePostSpec spec = (RequestQueuePostSpec) RequestQueuePostSpec
.newBuilder(req)
.setMessageId(messageId)
.setTopic(new Topic() {
@Override
public AsciiString name() {
return AsciiString.cached(unit.topic());
}
@Override
public void configure(ApplicationConfig cfg) {
}
}).build();
RequestWrapperFacade reqw = apiFactory.requestMapper().pack(
spec,
new ContextPropagator() {
@Override
public void injectContext(api.v1.Headers.Builder into) {
into.setMessageId(messageId.toString());
Optional.ofNullable(GrpcHeaders.CONTEXT_TRACE_ID.get()).ifPresent(v -> into.setTraceId(v));
Optional.ofNullable(GrpcHeaders.CONTEXT_BRAND_NAME.get()).ifPresent(v -> into.setBrandName(v));
}
}, timeout);
Optional> completable = Optional.empty();
CountDownLatch latch = new CountDownLatch(1);
try {
completable = logAndAccept(reqw, unit, latch);
if (completable.isEmpty()) {
}
} catch (Exception err) {
logger.error(err.getMessage(), err);
latch.countDown();
completable = Optional.of(convertUnhandledException(unit, err));
} finally {
}
if (completable.isPresent()) {
FluentFuture fluent = FluentFuture.from(completable.get());
fluent.addCallback(new PublishOperationOutcomeCallback<>(type, responseObserver), MoreExecutors.directExecutor());
}
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public WorkerCompletableTask schedule(WorkUnit unit, RequestWrapperFacade reqw, CountDownLatch latch) throws Throwable {
var body = reqw.body();
var span = span(bootstrap, unit, reqw);
var handler = Objects.requireNonNull(handlers.get(body.getTypeUrl()));
var callbackExecutor = MoreExecutors.directExecutor();
var tx = new EmbeddedTransactionalRequest<>(handler.requestType(), handler.newReply(), unit, reqw, latch);
var worker = workerFactory.worker(unit);
var sh = new SafeRequestHandler(reqw, apiFactory, stackTracer, span, unit, tx, handler);
var run = handler.decorate(topicRegistry, unit, sh);
var callback = new FutureCallback() {
@Override
public void onSuccess(Object result) {
}
@Override
public void onFailure(Throwable t) {
logger.error(t.getMessage(), t);
}
};
sh.setBootstrap(bootstrap);
if (handler.actorIsRequired()) {
FluentFuture.from(worker.actor(unit).submit(run)).addCallback(callback, callbackExecutor);
} else {
FluentFuture.from(worker.ifPresent(unit).submit(run)).addCallback(callback, callbackExecutor);
}
return sh.get();
}
private static Span span(Bootstrap bootstrap, WorkUnit record, RequestWrapperFacade reqw) {
var body = reqw.body();
var operation = PlatformUtil.toLowerUnderscore(body.getTypeUrl());
//
// ~ create child span
//
var buildSpan = bootstrap.tracer().buildSpan(operation);
var span = buildSpan.start();
span.setTag(MdcTags.MDC_MESSAGE_ID, reqw.headers().getMessageId());
if (Objects.nonNull(record.key())) {
AsciiString partitionKey = new AsciiString(record.key());
span.setTag(MdcTags.MDC_ROUTING_KEY, partitionKey.toString());
}
return span;
}
private class PublishOperationOutcomeCallback implements FutureCallback {
private final Class type;
private final StreamObserver responseObserver;
public PublishOperationOutcomeCallback(Class type, StreamObserver responseObserver) {
this.type = Objects.requireNonNull(type);
this.responseObserver = Objects.requireNonNull(responseObserver);
}
@Override
public void onSuccess(TransactionalRequestOutcome result) {
try {
postTemplate.publishNotifications(apiFactory.notifyTopic(), result);
postTemplate.publishEvents(apiFactory.eventsTopic(), result);
RESP resp = result.getReply().unpack(type);
responseObserver.onNext(resp);
responseObserver.onCompleted();
} catch (Exception err) {
responseObserver.onError(err);
}
}
@Override
public void onFailure(Throwable t) {
try {
responseObserver.onError(t);
} finally {
}
}
}
}