You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebClient发送Webhook时记录重试次数并保存请求详情至数据库的实现咨询

WebClient发送Webhook时记录重试次数并保存请求详情至数据库的实现咨询

嘿,看起来你已经在着手搭建Webhook的重试与日志记录功能了,这可是保障Webhook可靠性的核心环节!我来帮你梳理现有代码的优化方向,把每次请求的响应状态、响应体和重试次数完整存入数据库的需求落地。

核心需求复盘

你需要实现的是:

  • 用WebClient向指定URL发送Webhook请求
  • 请求失败时自动重试(最多5次,间隔10秒)
  • **每次请求(无论成功/失败)**都要记录:响应状态码、响应体、尝试次数到数据库

现有代码的优化点

你已经用到了Retry.fixedDelay和onStatus处理错误响应,但还需要完善两个关键部分:重试次数的准确追踪和全请求链路的日志记录(包括成功请求和每一次重试的失败请求)。

完整实现代码示例

1. 完善后的sendWebHook方法

import reactor.util.retry.Retry;
import java.time.Duration;
import java.time.LocalDateTime;

@SneakyThrows
public void sendWebHook(Transaction transaction) {
    // 定义重试策略:最多重试5次,每次间隔10秒,同时追踪重试次数
    RetryBackoffSpec retryStrategy = Retry.fixedDelay(5, Duration.ofSeconds(10))
            .doOnRetry(retrySignal -> {
                // totalRetries()是已重试的次数,尝试次数 = 已重试次数 + 1(第一次尝试是1,重试后依次递增)
                int attemptNum = retrySignal.totalRetries() + 1;
                log.info("Webhook请求重试中,第{}次尝试,交易ID:{}", attemptNum, transaction.getId());
            });

    GetTransactionResponse requestBody = transactionMapper.transactionToGetResponse(transaction);
    String targetUrl = transaction.getNotificationUrl();

    webClient.post()
            .uri(targetUrl)
            .body(Mono.just(requestBody), GetTransactionResponse.class)
            .retrieve()
            // 处理错误状态码:记录本次失败请求,然后抛出异常触发重试
            .onStatus(HttpStatusCode::isError, response -> {
                return response.toEntity(WebhookResponse.class)
                        .flatMap(errorResponse -> {
                            // 第一次失败是第1次尝试
                            saveWebhookLog(transaction, errorResponse, 1);
                            return Mono.error(new RuntimeException("Webhook请求失败,状态码:" + errorResponse.getStatusCode()));
                        });
            })
            // 处理成功请求:记录成功的请求详情
            .toEntity(WebhookResponse.class)
            .doOnSuccess(successResponse -> {
                saveWebhookLog(transaction, successResponse, 1);
            })
            // 绑定重试策略,捕获异常后自动重试
            .retryWhen(retryStrategy)
            // 处理最终重试失败的情况:记录最后一次尝试的失败详情
            .doOnError(finalError -> {
                int finalAttemptNum = 5 + 1; // 最多重试5次,加上第一次尝试,共6次
                // 构造失败响应实体用于记录
                WebhookResponse errorBody = new WebhookResponse();
                errorBody.setErrorMsg(finalError.getMessage());
                ResponseEntity<WebhookResponse> finalFailedResponse = 
                        new ResponseEntity<>(errorBody, HttpStatus.INTERNAL_SERVER_ERROR);
                saveWebhookLog(transaction, finalFailedResponse, finalAttemptNum);
            })
            .block(); // 同步场景用block,异步场景改用subscribe
}

2. 数据库保存方法saveWebhookLog

这个方法负责把请求详情持久化到数据库,需要接收尝试次数参数:

private void saveWebhookLog(Transaction transaction, ResponseEntity<WebhookResponse> responseEntity, int attemptNumber) {
    // 构造Webhook日志实体(根据你的数据库表结构调整)
    WebhookLog logEntity = new WebhookLog();
    logEntity.setTransactionId(transaction.getId());
    logEntity.setNotificationUrl(transaction.getNotificationUrl());
    logEntity.setAttemptNumber(attemptNumber);
    logEntity.setResponseStatusCode(responseEntity.getStatusCode().value());
    logEntity.setResponseBody(objectMapper.writeValueAsString(responseEntity.getBody()));
    // 可选:记录请求体,让日志更完整
    logEntity.setRequestBody(objectMapper.writeValueAsString(transactionMapper.transactionToGetResponse(transaction)));
    logEntity.setRequestTime(LocalDateTime.now());

    // 存入数据库
    webhookLogRepository.save(logEntity);
}

关键细节说明

  • 重试次数的准确追踪:通过retrySignal.totalRetries()获取已重试的次数,尝试次数等于已重试次数+1,比如第一次尝试失败后重试,totalRetries()为1,尝试次数就是2。
  • 全链路记录:不管是首次请求成功、首次请求失败触发重试,还是最终所有重试都失败,都会调用saveWebhookLog,确保每一次请求都有记录。
  • 灵活调整重试策略:如果需要指数退避(间隔时间递增),可以把Retry.fixedDelay换成Retry.backoff(5, Duration.ofSeconds(10))。
  • 异步场景适配:如果你的服务是异步架构,把block()换成subscribe(),并在subscribe的回调里处理成功/失败逻辑,避免阻塞线程。

额外注意事项

  • 确保saveWebhookLog方法是线程安全的,尤其是在高并发场景下。
  • 可以给WebClient添加超时设置,比如.timeout(Duration.ofSeconds(30)),避免请求长时间挂起。
  • 数据库表可以添加索引(比如transaction_id),方便后续查询某笔交易的所有Webhook请求记录。

备注:内容来源于stack exchange,提问作者Александр Кошкин

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 07:40:33