解决异步调用时zipkin链路跟踪问题

一、问题

使用CompletableFuture异步调用时zipkintraceId无法跟踪并且feign调用链路也跟踪不到

public void testFuture() {

        List<CompletableFuture<String>> futureList = Lists.newArrayList();

        try {

            //分账证明材料 ID,返回的是银联的图片Id

            futureList.add(CompletableFuture.supplyAsync(() -> testAsync("testA:" + UuidUtils.generateUuid()), asyncImgExecutor).whenComplete((result, exception) -> {

                if (StringUtils.isNotBlank(result)) {

                    log.info("result:{}", result);

                }

            }));

            //上传接收方证明文件照片(营业执照),返回的是银联的图片Id

            futureList.add(CompletableFuture.supplyAsync(() -> testAsync("testB:" + UuidUtils.generateUuid()), asyncImgExecutor).whenComplete((result, exception) -> {

                if (StringUtils.isNotBlank(result)) {

                    log.info("result:{}", result);

                }

            }));

            //等到所有异步任务完成

            CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();

        catch (Exception e) {

            throw PycExceptionBuilder.createNseException(ErrorCodeEnum.EXTERNAL_ERROR, "分账需求调用银联【上传分账接收方进件文件】接口失败", e);

        }

    }

    private String testAsync(String s) {

        log.info("testAsync:{}", s);

        return s;

    }

二、解决方案

1.增加zipkin装饰器

package com.yingzi.bizcenter.payment.common.utils;

import com.yingzi.bizcenter.common.zipkin.ZipkinHelper;

import lombok.extern.slf4j.Slf4j;

import org.springframework.core.task.TaskDecorator;

/**

 * @Author: chenyangu

 * @Date: 2021/8/16 17:05

 * @Description: zipkin装饰器

 */

@Slf4j

public class ZipkinTaskDecorator implements TaskDecorator {

    private ZipkinHelper zipkinHelper;

    public ZipkinTaskDecorator(ZipkinHelper zipkinHelper) {

        this.zipkinHelper = zipkinHelper;

    }

    @Override

    public Runnable decorate(Runnable runnable) {

        return zipkinHelper.wrap(runnable);

    }

}

1.自定义线程池,将装饰器放入线程池中

package com.yingzi.bizcenter.payment.interfaces.config;

import com.yingzi.bizcenter.common.zipkin.ZipkinHelper;

import com.yingzi.bizcenter.payment.common.utils.ZipkinTaskDecorator;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

import java.util.concurrent.ThreadPoolExecutor;

/**

 * @Author: chenyangu

 * @Date: 2021/8/16 16:57

 * @Description: 自定义线程池

 */

@Configuration

@Slf4j

public class ThreadPoolConfig {

    private int corePoolSize = 10;

    private int maxPoolSize = 20;

    private int queueCapacity = 1000;

    private int keepAliveSeconds = 800;

    @Autowired

    ZipkinHelper zipkinHelper;

    @Bean("asyncImgExecutor")

    public Executor asyncImgExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        //配置核心线程数

        executor.setCorePoolSize(corePoolSize);

        //配置最大线程数

        executor.setMaxPoolSize(maxPoolSize);

        //配置队列大小

        executor.setQueueCapacity(queueCapacity);

        // 空闲的多余线程最大存活时间

        executor.setKeepAliveSeconds(keepAliveSeconds);

        //配置线程池中的线程的名称前缀

        executor.setThreadNamePrefix("async-resource-schedule-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务

        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        //zipkin链路调用

        executor.setTaskDecorator(new ZipkinTaskDecorator(zipkinHelper));

        //执行初始化

        executor.initialize();

        return executor;

    }

}

3.CompletableFuture指定自定义线程池

CompletableFuture.supplyAsync(() -> downloadAndUploadFile(reqDto.getBankAccountFileId()), asyncImgExecutor)

@Component
public class ZipkinHelper {
    @Autowired
    private Tracer tracer;

    public ZipkinHelper() {
    }

    public Runnable wrap(Runnable runnable) {
        Span currentSpan = this.tracer.currentSpan();
        return () -> {
            SpanInScope scope = this.tracer.withSpanInScope(currentSpan);
            Throwable var4 = null;

            try {
                Span span = this.tracer.nextSpan();
                MDC.put("X-B3-TraceId", span.context().traceIdString());
                MDC.put("X-B3-SpanId", span.context().spanIdString());
                MDC.put("X-B3-ParentSpanId", span.context().parentIdString());
                span.name("new_thread_started").kind(Kind.SERVER).tag("thread_id", Thread.currentThread().getId() + "").tag("thread_name", Thread.currentThread().getName() + "");
                span.start();

                try {
                    SpanInScope ws = this.tracer.withSpanInScope(span);
                    Throwable var7 = null;

                    try {
                        runnable.run();
                    } catch (Throwable var44) {
                        var7 = var44;
                        throw var44;
                    } finally {
                        if (ws != null) {
                            if (var7 != null) {
                                try {
                                    ws.close();
                                } catch (Throwable var43) {
                                    var7.addSuppressed(var43);
                                }
                            } else {
                                ws.close();
                            }
                        }

                    }
                } catch (Error | RuntimeException var46) {
                    span.error(var46);
                    throw var46;
                } finally {
                    span.finish();
                }
            } catch (Throwable var48) {
                var4 = var48;
                throw var48;
            } finally {
                if (scope != null) {
                    if (var4 != null) {
                        try {
                            scope.close();
                        } catch (Throwable var42) {
                            var4.addSuppressed(var42);
                        }
                    } else {
                        scope.close();
                    }
                }

            }

        };
    }

    public <T> Callable<T> wrap(Callable<T> callable) {
        Span currentSpan = this.tracer.currentSpan();
        return () -> {
            SpanInScope scope = this.tracer.withSpanInScope(currentSpan);
            Throwable var4 = null;

            Object var8;
            try {
                Span span = this.tracer.nextSpan();
                MDC.put("X-B3-TraceId", span.context().traceIdString());
                MDC.put("X-B3-SpanId", span.context().spanIdString());
                MDC.put("X-B3-ParentSpanId", span.context().parentIdString());
                span.name("new_thread_started").kind(Kind.SERVER).tag("thread_id", Thread.currentThread().getId() + "").tag("thread_name", Thread.currentThread().getName() + "");
                span.start();

                try {
                    SpanInScope ws = this.tracer.withSpanInScope(span);
                    Throwable var7 = null;

                    try {
                        var8 = callable.call();
                    } catch (Throwable var45) {
                        var8 = var45;
                        var7 = var45;
                        throw var45;
                    } finally {
                        if (ws != null) {
                            if (var7 != null) {
                                try {
                                    ws.close();
                                } catch (Throwable var44) {
                                    var7.addSuppressed(var44);
                                }
                            } else {
                                ws.close();
                            }
                        }

                    }
                } catch (Error | RuntimeException var47) {
                    span.error(var47);
                    throw var47;
                } finally {
                    span.finish();
                }
            } catch (Throwable var49) {
                var4 = var49;
                throw var49;
            } finally {
                if (scope != null) {
                    if (var4 != null) {
                        try {
                            scope.close();
                        } catch (Throwable var43) {
                            var4.addSuppressed(var43);
                        }
                    } else {
                        scope.close();
                    }
                }

            }

            return var8;
        };
    }
}
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值