利用Java CompletableFuture优化企业微信批量消息发送的异步编排
在企业级应用中,通过企业微信向大量成员或客户群发通知是常见需求。若采用同步串行发送,不仅耗时长,还会因单个请求失败阻塞整体流程。Java 8 引入的 CompletableFuture 提供了强大的异步编排能力,可显著提升吞吐量与容错性。本文以 wlkankan.cn 包结构为例,展示如何基于 CompletableFuture 实现高并发、带限流与失败重试的企业微信消息批量发送系统。
基础异步发送框架
首先定义消息实体与发送客户端:
java
package wlkankan.cn.message.model;
public class WeComMessage {
private String userId;
private String content;
private String accessToken;
// constructors, getters, setters
}
java
package wlkankan.cn.message.client;
import java.util.concurrent.CompletableFuture;
public class WeComApiClient {
public static CompletableFuture<String> sendMessageAsync(WeComMessage msg) {
return CompletableFuture.supplyAsync(() -> {
try {
// 模拟HTTP调用企业微信API
Thread.sleep(200); // 网络延迟
if (Math.random() < 0.1) { // 10% 模拟失败
throw new RuntimeException("Send failed for " + msg.getUserId());
}
return "OK:" + msg.getUserId();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}

批量发送与结果聚合
使用 CompletableFuture.allOf() 并行发送并等待全部完成:
java
package wlkankan.cn.message.service;
import wlkankan.cn.message.client.WeComApiClient;
import wlkankan.cn.message.model.WeComMessage;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class BatchMessageService {
public List<String> sendBatch(List<WeComMessage> messages) {
List<CompletableFuture<String>> futures = messages.stream()
.map(WeComApiClient::sendMessageAsync)
.collect(Collectors.toList());
CompletableFuture<Void> allDone = CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0])
);
allDone.join(); // 阻塞等待全部完成
return futures.stream()
.map(f -> {
try {
return f.get();
} catch (Exception e) {
return "ERROR:" + e.getCause().getMessage();
}
})
.collect(Collectors.toList());
}
}
引入信号量限流防止API过载
企业微信API有严格的QPS限制(如2000/分钟)。为避免触发限流,需控制并发数:
java
package wlkankan.cn.message.service;
import java.util.concurrent.Semaphore;
import java.util.concurrent.CompletableFuture;
public class RateLimitedWeComClient {
private final Semaphore semaphore;
public RateLimitedWeComClient(int maxConcurrent) {
this.semaphore = new Semaphore(maxConcurrent);
}
public CompletableFuture<String> sendMessageWithLimit(WeComMessage msg) {
return CompletableFuture.supplyAsync(() -> {
try {
semaphore.acquire();
try {
// 调用真实API
return WeComApiClient.sendMessage(msg).get();
} finally {
semaphore.release();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
});
}
}
失败重试机制
对失败请求自动重试最多3次:
java
package wlkankan.cn.message.retry;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public class RetryableFuture {
public static <T> CompletableFuture<T> retry(Supplier<CompletableFuture<T>> action, int maxRetries, long delayMs) {
CompletableFuture<T> result = new CompletableFuture<>();
attempt(action, maxRetries, delayMs, result);
return result;
}
private static <T> void attempt(Supplier<CompletableFuture<T>> action, int retriesLeft, long delayMs, CompletableFuture<T> result) {
action.get().whenComplete((value, throwable) -> {
if (throwable == null) {
result.complete(value);
} else if (retriesLeft > 0) {
try {
TimeUnit.MILLISECONDS.sleep(delayMs);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
result.completeExceptionally(e);
return;
}
attempt(action, retriesLeft - 1, delayMs, result);
} else {
result.completeExceptionally(throwable);
}
});
}
}
集成到发送逻辑中:
java
package wlkankan.cn.message.service;
import wlkankan.cn.message.retry.RetryableFuture;
import wlkankan.cn.message.client.WeComApiClient;
import wlkankan.cn.message.model.WeComMessage;
import java.util.concurrent.CompletableFuture;
public class ResilientMessageService {
public CompletableFuture<String> sendWithRetry(WeComMessage msg) {
return RetryableFuture.retry(
() -> WeComApiClient.sendMessageAsync(msg),
3,
500
).exceptionally(ex -> "FAILED_AFTER_RETRY:" + msg.getUserId());
}
}
完整批量发送流程
组合限流、重试与结果收集:
java
package wlkankan.cn.message.service;
import wlkankan.cn.message.model.WeComMessage;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class EnterpriseBatchSender {
private final RateLimitedWeComClient client = new RateLimitedWeComClient(50); // 限制50并发
public List<String> sendAll(List<WeComMessage> messages) {
List<CompletableFuture<String>> futures = messages.stream()
.map(msg -> client.sendMessageWithLimit(msg)
.handle((res, ex) -> ex == null ? res : "INITIAL_FAIL:" + msg.getUserId())
.thenCompose(result -> {
if (result.startsWith("INITIAL_FAIL")) {
return new ResilientMessageService().sendWithRetry(
new WeComMessage(/* reconstruct from result */)
);
}
return CompletableFuture.completedFuture(result);
}))
.collect(Collectors.toList());
CompletableFuture<Void> all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
all.join();
return futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
}
通过 CompletableFuture 的链式编排,wlkankan.cn.message 模块实现了高并发、带限流、自动重试的企业微信批量消息发送系统,在保障API合规的同时极大提升了发送效率与稳定性。