我正在编写的一项服务位于客户端之间,该服务将接收批量请求并将其分别发送到需要分解为单个请求的供应商应用程序。
该供应商应用程序具有一个带有令牌帽的rest API,该API每4小时失效一次。它还会在重新启动时以及在其他各种情况下失效。我想优雅地处理这个问题。
出于性能方面的考虑,我分析了可以向供应商应用程序发送15个并发请求,这样就不必等待整个往返。
我现在要解决的问题是在进行批量操作时如何处理令牌/ cookie过期的情况。
我的代码大致如下所示:Executor和许多其他简洁内容:
@RestController("/upload")
public BulkController {
@Autowired RestClient restClient;
@PostMapping
public bulkUpload(@RequestBody BulkType bulk){
restClient.bulkupload(bulk);
}
}
public RestClient {
/* Credentials and other initializations */
@Autowired AsnycClient asyncClient;
@Async
private
public bulkupload(BulkType bulk){
for( Single single: bulk.getEntries()){
asyncClient.upload(single);
}
}
}
public AsnycClient {
/* Credentials and other initializations */
private static String token = null;
@Async
public uploadSingle(Single single){
Result result = vendorClient.upload(single, token);
if( result.needsAuthentication()){
token = vendorClient.authenticate(credentials);
result = vendorClient.upload(single, token);
}
}
}
我最讨厌的部分是如何处理在此批量处理过程中的第一次请求中令牌已过期或无效的情况。
现在正在发生的事情是,前10个左右的请求是使用旧令牌发送的,它们都以needsAuthentication(true)
返回。因此,我有10个打到authenticate()
的电话,又有10个打给供应商应用程序的电话,总共有30个电话。
我想尝试的是使authenticate()
正确发生的正确方法,以便拥有needsAuthentication(true)
的人中的前1个人执行authenticate()
,其他人能够以某种方式检测到该问题,并使用令牌的新值。
让我想到我问题的天真的方法就是运行这个:
public AsnycClient {
/* Credentials and other initializations */
private static String token = null;
@Async
public uploadSingle(Single single){
Result result = vendorClient.upload(single, token);
if( result.needsAuthentication()){
synchronized (token){
token = vendorClient.authenticate(credentials);
}
result = vendorClient.upload(single, token);
}
}
}
虽然可以确保所有线程都协作,一次登录一个,但实际上并不能帮助我跳过昂贵的authenticate()
步骤。
我满足需求的另一种尝试是这样做:
public AsnycClient {
private static HashMap<String, String> refreshedTokenMap = new HashMap<String, String>();
/* Credentials and other initializations */
private static String token = null;
@Async
public uploadSingle(Single single){
String currentToken = token;
Result result = vendorClient.upload(single, currentToken);
if( result.needsAuthentication()){
synchronized (token){
if( refreshedTokenMap.containsKey(currentToken)){
// the current token is one that has been renewed, and so 'token' will contain renewed value
}else{
token = vendorClient.authenticate(credentials);
refreshedTokenMap.put(currentToken, token);
}
}
result = vendorClient.upload(single, token);
}
}
}
使用refreshedTokenMap
,我可以知道在当前线程中是否已经更新了启动该函数的令牌。
没有任何办法,一旦使用原始令牌的所有线程执行完毕,就删除该Map
中的条目。
有人能解决这个问题或其他指南吗?
谢谢。