All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.turbospaces.gcp.pubsub.producer.PubsubPostTemplate Maven / Gradle / Ivy

There is a newer version: 2.0.33
Show newest version
package com.turbospaces.gcp.pubsub.producer;

import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

import org.slf4j.MDC;

import com.google.cloud.spring.pubsub.support.PublisherFactory;
import com.google.protobuf.Any;
import com.google.pubsub.v1.PubsubMessage;
import com.turbospaces.annotations.NotInTransactionGuard;
import com.turbospaces.api.facade.MDCToHeadersContexPropagator;
import com.turbospaces.api.facade.RequestWrapperFacade;
import com.turbospaces.cfg.ApplicationProperties;
import com.turbospaces.dispatch.EventQueuePostSpec;
import com.turbospaces.dispatch.NotifyQueuePostSpec;
import com.turbospaces.dispatch.QueuePostSpec;
import com.turbospaces.dispatch.RequestQueuePostSpec;
import com.turbospaces.http.HttpProto;
import com.turbospaces.mdc.MdcTags;
import com.turbospaces.rpc.DefaultRequestReplyMapper;
import com.turbospaces.rpc.DefaultWrappedQueuePost;
import com.turbospaces.rpc.QueuePostTemplate;
import com.turbospaces.rpc.WrappedQueuePost;

import api.v1.ApiFactory;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.gpubsub.impl.PubsubWithRoutingKeyMessageWriterImpl;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.Tracer.SpanBuilder;
import io.opentracing.propagation.Format.Builtin;
import jakarta.inject.Inject;

public class PubsubPostTemplate extends DefaultPubsubPublisher implements QueuePostTemplate {
    private final Tracer tracer;
    private final ApiFactory apiFactory;
    private final DefaultRequestReplyMapper mapper;
    private final Supplier defaultTimeout;

    @Inject
    public PubsubPostTemplate(
            ApplicationProperties props,
            Tracer tracer,
            ApiFactory apiFactory,
            DefaultRequestReplyMapper mapper,
            PublisherFactory producerFactory,
            Supplier timeout) throws Exception {
        super(props, producerFactory);
        this.tracer = Objects.requireNonNull(tracer);
        this.apiFactory = Objects.requireNonNull(apiFactory);
        this.mapper = Objects.requireNonNull(mapper);
        this.defaultTimeout = Objects.requireNonNull(timeout);
    }
    @Override
    @NotInTransactionGuard
    public WrappedQueuePost sendReq(RequestQueuePostSpec spec) {
        Duration operationTimeout = spec.timeout().orElse(defaultTimeout.get());
        long now = System.currentTimeMillis();
        String qualifier = spec.topic().name().toString();
        UUID messageId = spec.messageId();

        CloudEventBuilder eventTemplate = apiFactory.eventTemplate();
        RequestWrapperFacade reqw = apiFactory.requestMapper().pack(spec, new MDCToHeadersContexPropagator(), defaultTimeout.get());
        String typeUrl = reqw.body().getTypeUrl();

        CloudEventBuilder event = eventTemplate.newBuilder()
                .withId(messageId.toString())
                .withTime(OffsetDateTime.ofInstant(Instant.ofEpochMilli(now), UTC))
                .withType(typeUrl);

        var record = PubsubMessage.newBuilder();
        record.setData(reqw.toByteString());
        if (spec.routingKey().isPresent()) {
            record.setOrderingKey(spec.routingKey().get().toString());
        }
        record.putAttributes(HttpProto.HEADER_X_TIMESTAMP, String.valueOf(now));
        var post = span(spec, record);
        var messageWriter = new PubsubWithRoutingKeyMessageWriterImpl(record);
        var future = mapper.acquire(messageId, operationTimeout);
        var callback = new LoggingCallback(typeUrl, messageId, spec.topic(), now) {
            @Override
            public void onSuccess(String result) {
                super.onSuccess(result);
                post.finish();
            }
            @Override
            public void onFailure(Throwable ex) {
                super.onFailure(ex);
                future.setException(ex);
                post.finish();
            }
        };

        publish(qualifier, messageWriter.writeBinary(event.build()), new BiConsumer() {
            @Override
            public void accept(String result, Throwable ex) {
                if (Objects.nonNull(ex)) {
                    callback.onFailure(ex);
                } else {
                    callback.onSuccess(result);
                }
            }
        });

        return new DefaultWrappedQueuePost(future, reqw);
    }
    @Override
    @NotInTransactionGuard
    public CompletableFuture sendEvent(EventQueuePostSpec spec) {
        Any any = spec.pack();
        long now = System.currentTimeMillis();
        String qualifier = spec.topic().name().toString();
        String typeUrl = any.getTypeUrl();
        UUID messageId = spec.messageId();

        var record = PubsubMessage.newBuilder();
        record.setData(any.toByteString());
        if (spec.routingKey().isPresent()) {
            record.setOrderingKey(spec.routingKey().get().toString());
        }

        var traceId = MDC.get(MdcTags.MDC_TRACE_ID);
        if (Objects.nonNull(traceId)) {
            record.putAttributes(MdcTags.MDC_TRACE_ID, traceId);
        }

        CloudEventBuilder eventTemplate = CloudEventBuilder.v1().withSource(URI.create(props.CLOUD_APP_ID.get()));
        CloudEventBuilder event = eventTemplate.newBuilder()
                .withId(messageId.toString())
                .withTime(OffsetDateTime.ofInstant(Instant.ofEpochMilli(now), UTC))
                .withType(typeUrl);

        var post = span(spec, record);
        var messageWriter = new PubsubWithRoutingKeyMessageWriterImpl(record);
        var callback = new LoggingCallback(typeUrl, messageId, spec.topic(), now) {
            @Override
            public void onSuccess(String result) {
                super.onSuccess(result);
                post.finish();
            }
            @Override
            public void onFailure(Throwable ex) {
                super.onFailure(ex);
                post.finish();
            }
        };

        return publish(qualifier, messageWriter.writeBinary(event.build()), new BiConsumer() {
            @Override
            public void accept(String result, Throwable ex) {
                if (Objects.nonNull(ex)) {
                    callback.onFailure(ex);
                } else {
                    callback.onSuccess(result);
                }
            }
        });
    }
    @Override
    @NotInTransactionGuard
    public CompletableFuture sendNotify(NotifyQueuePostSpec spec) {
        long now = System.currentTimeMillis();
        String qualifier = spec.topic().name().toString();
        String typeUrl = spec.body().getTypeUrl();
        UUID messageId = spec.messageId();

        var record = PubsubMessage.newBuilder();
        record.setData(spec.toByteString());
        if (spec.routingKey().isPresent()) {
            record.setOrderingKey(spec.routingKey().get().toString());
        }

        var traceId = MDC.get(MdcTags.MDC_TRACE_ID);
        if (Objects.nonNull(traceId)) {
            record.putAttributes(MdcTags.MDC_TRACE_ID, traceId);
        }

        CloudEventBuilder eventTemplate = CloudEventBuilder.v1().withSource(URI.create(props.CLOUD_APP_ID.get()));
        CloudEventBuilder event = eventTemplate.newBuilder()
                .withId(messageId.toString())
                .withTime(OffsetDateTime.ofInstant(Instant.ofEpochMilli(now), UTC))
                .withType(typeUrl);

        var post = span(spec, record);
        var messageWriter = new PubsubWithRoutingKeyMessageWriterImpl(record);
        var callback = new LoggingCallback(typeUrl, messageId, spec.topic(), now) {
            @Override
            public void onSuccess(String result) {
                super.onSuccess(result);
                post.finish();
            }
            @Override
            public void onFailure(Throwable ex) {
                super.onFailure(ex);
                post.finish();
            }
        };

        return publish(qualifier, messageWriter.writeBinary(event.build()), new BiConsumer() {
            @Override
            public void accept(String result, Throwable ex) {
                if (Objects.nonNull(ex)) {
                    callback.onFailure(ex);
                } else {
                    callback.onSuccess(result);
                }
            }
        });
    }
    private Span span(QueuePostSpec spec, PubsubMessage.Builder recordBuilder) {
        Span span = tracer.activeSpan();
        SpanBuilder post = tracer.buildSpan("pubsub-post");

        if (Objects.nonNull(span)) {
            tracer.inject(span.context(), Builtin.TEXT_MAP, new PubsubSpanContextWriter(recordBuilder));
            return post.asChildOf(span).start();
        }

        return post.start();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy