Skip to content

Commit 402df05

Browse files
committed
Support adding a trace information to cache UUID on demand
1 parent f2fa433 commit 402df05

File tree

3 files changed

+244
-4
lines changed

3 files changed

+244
-4
lines changed

src/main/java/org/prebid/server/cache/CoreCacheService.java

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public class CoreCacheService {
6363
private static final Logger logger = LoggerFactory.getLogger(CoreCacheService.class);
6464

6565
private static final String BID_WURL_ATTRIBUTE = "wurl";
66+
private static final String TRACE_INFO_SEPARATOR = "-";
67+
private static final int DATACENTER_REGION_LENGTH = 4;
6668

6769
private final HttpClient httpClient;
6870
private final URL endpointUrl;
@@ -78,13 +80,18 @@ public class CoreCacheService {
7880
private final MultiMap cacheHeaders;
7981
private final Map<String, List<String>> debugHeaders;
8082

83+
private final boolean appendTraceInfoToCacheId;
84+
private final String datacenterRegion;
85+
8186
public CoreCacheService(
8287
HttpClient httpClient,
8388
URL endpointUrl,
8489
String cachedAssetUrlTemplate,
8590
long expectedCacheTimeMs,
8691
String apiKey,
8792
boolean isApiKeySecured,
93+
boolean appendTraceInfoToCacheId,
94+
String datacenterRegion,
8895
VastModifier vastModifier,
8996
EventsService eventsService,
9097
Metrics metrics,
@@ -107,6 +114,9 @@ public CoreCacheService(
107114
? HttpUtil.headers().add(HttpUtil.X_PBC_API_KEY_HEADER, Objects.requireNonNull(apiKey))
108115
: HttpUtil.headers();
109116
debugHeaders = HttpUtil.toDebugHeaders(cacheHeaders);
117+
118+
this.appendTraceInfoToCacheId = appendTraceInfoToCacheId;
119+
this.datacenterRegion = normalizeDatacenterRegion(datacenterRegion);
110120
}
111121

112122
public String getEndpointHost() {
@@ -211,6 +221,7 @@ private List<CachedCreative> updatePutObjects(List<BidPutObject> bidPutObjects,
211221
.bidid(null)
212222
.bidder(null)
213223
.timestamp(null)
224+
.key(resolveCacheKey(accountId, putObject.getKey()))
214225
.value(vastModifier.modifyVastXml(isEventsEnabled,
215226
allowedBidders,
216227
putObject,
@@ -268,7 +279,8 @@ private Future<CacheServiceResult> doCacheOpenrtb(List<CacheBid> bids,
268279
final List<CachedCreative> cachedCreatives = Stream.concat(
269280
bids.stream().map(cacheBid ->
270281
createJsonPutObjectOpenrtb(cacheBid, accountId, eventsContext)),
271-
videoBids.stream().map(videoBid -> createXmlPutObjectOpenrtb(videoBid, requestId, hbCacheId)))
282+
videoBids.stream().map(videoBid ->
283+
createXmlPutObjectOpenrtb(videoBid, requestId, hbCacheId, accountId)))
272284
.collect(Collectors.toCollection(ArrayList::new));
273285

274286
if (cachedCreatives.isEmpty()) {
@@ -385,26 +397,34 @@ private CachedCreative createJsonPutObjectOpenrtb(CacheBid cacheBid,
385397
bidObjectNode.put(BID_WURL_ATTRIBUTE, eventUrl);
386398
}
387399

400+
final String resolvedCacheKey = resolveCacheKey(accountId);
401+
388402
final BidPutObject payload = BidPutObject.builder()
389403
.aid(eventsContext.getAuctionId())
390404
.type("json")
405+
.key(resolvedCacheKey)
391406
.value(bidObjectNode)
392407
.ttlseconds(cacheBid.getTtl())
393408
.build();
394409

395410
return CachedCreative.of(payload, creativeSizeFromAdm(bid.getAdm()));
396411
}
397412

398-
private CachedCreative createXmlPutObjectOpenrtb(CacheBid cacheBid, String requestId, String hbCacheId) {
413+
private CachedCreative createXmlPutObjectOpenrtb(CacheBid cacheBid,
414+
String requestId,
415+
String hbCacheId,
416+
String accountId) {
399417
final BidInfo bidInfo = cacheBid.getBidInfo();
400418
final Bid bid = bidInfo.getBid();
401419
final String vastXml = bid.getAdm();
402420

403-
final String customCacheKey = resolveCustomCacheKey(hbCacheId, bidInfo.getCategory());
421+
final String resolvedCacheKey = resolveCacheKey(accountId, hbCacheId);
422+
final String customCacheKey = resolveCustomCacheKey(resolvedCacheKey, bidInfo.getCategory());
404423

405424
final BidPutObject payload = BidPutObject.builder()
406425
.aid(requestId)
407426
.type("xml")
427+
.key(customCacheKey != null ? customCacheKey : resolvedCacheKey)
408428
.value(vastXml != null ? new TextNode(vastXml) : null)
409429
.ttlseconds(cacheBid.getTtl())
410430
.key(customCacheKey)
@@ -553,4 +573,48 @@ private BidCacheRequest toBidCacheRequest(List<CachedCreative> cachedCreatives)
553573
.map(CachedCreative::getPayload)
554574
.toList());
555575
}
576+
577+
private String resolveCacheKey(String accountId) {
578+
return resolveCacheKey(accountId, null);
579+
}
580+
581+
// hbCacheId is accepted here to have a backwards-compatibility with video category mapping
582+
private String resolveCacheKey(String accountId, String hbCacheId) {
583+
if (!appendTraceInfoToCacheId) {
584+
return hbCacheId;
585+
}
586+
587+
// no need to have additional separator if datacenter name won't be added
588+
final boolean isDatacenterNamePopulated = StringUtils.isNotBlank(datacenterRegion);
589+
final int separatorCount = isDatacenterNamePopulated ? 2 : 1;
590+
final int accountIdLength = accountId.length();
591+
final int traceInfoLength = isDatacenterNamePopulated
592+
? accountIdLength + DATACENTER_REGION_LENGTH + separatorCount
593+
: accountIdLength + separatorCount;
594+
595+
final String cacheKey = hbCacheId != null ? hbCacheId : idGenerator.generateId();
596+
if (cacheKey != null && traceInfoLength < cacheKey.length()) {
597+
final String substring = cacheKey.substring(0, cacheKey.length() - traceInfoLength);
598+
return isDatacenterNamePopulated
599+
? accountId + TRACE_INFO_SEPARATOR + datacenterRegion + TRACE_INFO_SEPARATOR + substring
600+
: accountId + TRACE_INFO_SEPARATOR + substring;
601+
} else {
602+
return hbCacheId;
603+
}
604+
}
605+
606+
private String normalizeDatacenterRegion(String datacenterRegion) {
607+
if (datacenterRegion == null) {
608+
return null;
609+
}
610+
611+
return switch (datacenterRegion) {
612+
case "eu-west" -> "ams3";
613+
case "eu-central" -> "fra2";
614+
case "us-east" -> "iad2";
615+
case "us-west" -> "sjc2";
616+
case "apac" -> "sin1";
617+
default -> datacenterRegion.length() > 4 ? datacenterRegion.substring(0, 4) : datacenterRegion;
618+
};
619+
}
556620
}

src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ CoreCacheService cacheService(
164164
@Value("${auction.cache.expected-request-time-ms}") long expectedCacheTimeMs,
165165
@Value("${pbc.api.key:#{null}}") String apiKey,
166166
@Value("${cache.api-key-secured:false}") boolean apiKeySecured,
167+
@Value("${cache.append-trace-info-to-cache-id:false}") boolean appendTraceInfoToCacheId,
168+
@Value("${datacenter-region:#{null}}") String datacenterRegion,
167169
VastModifier vastModifier,
168170
EventsService eventsService,
169171
HttpClient httpClient,
@@ -178,6 +180,8 @@ CoreCacheService cacheService(
178180
expectedCacheTimeMs,
179181
apiKey,
180182
apiKeySecured,
183+
appendTraceInfoToCacheId,
184+
datacenterRegion,
181185
vastModifier,
182186
eventsService,
183187
metrics,

src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ public void setUp() throws MalformedURLException, JsonProcessingException {
111111
100L,
112112
null,
113113
false,
114+
false,
115+
null,
114116
vastModifier,
115117
eventsService,
116118
metrics,
@@ -385,6 +387,8 @@ public void cacheBidsOpenrtbShouldUseApiKeyWhenProvided() throws MalformedURLExc
385387
100L,
386388
"ApiKey",
387389
true,
390+
false,
391+
null,
388392
vastModifier,
389393
eventsService,
390394
metrics,
@@ -810,6 +814,8 @@ public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLExce
810814
100L,
811815
"ApiKey",
812816
true,
817+
false,
818+
null,
813819
vastModifier,
814820
eventsService,
815821
metrics,
@@ -827,7 +833,7 @@ public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLExce
827833

828834
// when
829835
target.cachePutObjects(
830-
asList(firstBidPutObject),
836+
singletonList(firstBidPutObject),
831837
true,
832838
singleton("bidder1"),
833839
"account",
@@ -839,6 +845,172 @@ public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLExce
839845
.isEqualTo("ApiKey");
840846
}
841847

848+
@Test
849+
public void cachePutObjectsShouldPrependTraceInfoWhenEnabled() throws IOException {
850+
// given
851+
target = new CoreCacheService(
852+
httpClient,
853+
new URL("http://cache-service/cache"),
854+
"http://cache-service-host/cache?uuid=",
855+
100L,
856+
"ApiKey",
857+
false,
858+
true,
859+
null,
860+
vastModifier,
861+
eventsService,
862+
metrics,
863+
clock,
864+
idGenerator,
865+
jacksonMapper);
866+
867+
given(idGenerator.generateId()).willReturn("high-entropy-cache-id");
868+
869+
final BidPutObject firstBidPutObject = BidPutObject.builder()
870+
.type("json")
871+
.bidid("bidId1")
872+
.bidder("bidder1")
873+
.timestamp(1L)
874+
.value(new TextNode("vast"))
875+
.build();
876+
final BidPutObject secondBidPutObject = BidPutObject.builder()
877+
.type("xml")
878+
.bidid("bidId2")
879+
.bidder("bidder2")
880+
.timestamp(1L)
881+
.value(new TextNode("VAST"))
882+
.build();
883+
final BidPutObject thirdBidPutObject = BidPutObject.builder()
884+
.type("text")
885+
.bidid("bidId3")
886+
.bidder("bidder3")
887+
.timestamp(1L)
888+
.value(new TextNode("VAST"))
889+
.build();
890+
891+
given(vastModifier.modifyVastXml(any(), any(), any(), any(), anyString()))
892+
.willReturn(new TextNode("modifiedVast"))
893+
.willReturn(new TextNode("VAST"))
894+
.willReturn(new TextNode("updatedVast"));
895+
896+
// when
897+
target.cachePutObjects(
898+
asList(firstBidPutObject, secondBidPutObject, thirdBidPutObject),
899+
true,
900+
singleton("bidder1"),
901+
"account",
902+
"pbjs",
903+
timeout);
904+
905+
// then
906+
final BidPutObject modifiedFirstBidPutObject = firstBidPutObject.toBuilder()
907+
.bidid(null)
908+
.bidder(null)
909+
.timestamp(null)
910+
.key("account-high-entropy-")
911+
.value(new TextNode("modifiedVast"))
912+
.build();
913+
final BidPutObject modifiedSecondBidPutObject = secondBidPutObject.toBuilder()
914+
.bidid(null)
915+
.bidder(null)
916+
.timestamp(null)
917+
.key("account-high-entropy-")
918+
.build();
919+
final BidPutObject modifiedThirdBidPutObject = thirdBidPutObject.toBuilder()
920+
.bidid(null)
921+
.bidder(null)
922+
.timestamp(null)
923+
.key("account-high-entropy-")
924+
.value(new TextNode("updatedVast"))
925+
.build();
926+
927+
assertThat(captureBidCacheRequest().getPuts())
928+
.containsExactly(modifiedFirstBidPutObject, modifiedSecondBidPutObject, modifiedThirdBidPutObject);
929+
}
930+
931+
@Test
932+
public void cachePutObjectsShouldPrependTraceInfoWithDatacenterWhenEnabled() throws IOException {
933+
// given
934+
target = new CoreCacheService(
935+
httpClient,
936+
new URL("http://cache-service/cache"),
937+
"http://cache-service-host/cache?uuid=",
938+
100L,
939+
"ApiKey",
940+
false,
941+
true,
942+
"apac",
943+
vastModifier,
944+
eventsService,
945+
metrics,
946+
clock,
947+
idGenerator,
948+
jacksonMapper);
949+
950+
given(idGenerator.generateId()).willReturn("high-entropy-cache-id");
951+
952+
final BidPutObject firstBidPutObject = BidPutObject.builder()
953+
.type("json")
954+
.bidid("bidId1")
955+
.bidder("bidder1")
956+
.timestamp(1L)
957+
.value(new TextNode("vast"))
958+
.build();
959+
final BidPutObject secondBidPutObject = BidPutObject.builder()
960+
.type("xml")
961+
.bidid("bidId2")
962+
.bidder("bidder2")
963+
.timestamp(1L)
964+
.value(new TextNode("VAST"))
965+
.build();
966+
final BidPutObject thirdBidPutObject = BidPutObject.builder()
967+
.type("text")
968+
.bidid("bidId3")
969+
.bidder("bidder3")
970+
.timestamp(1L)
971+
.value(new TextNode("VAST"))
972+
.build();
973+
974+
given(vastModifier.modifyVastXml(any(), any(), any(), any(), anyString()))
975+
.willReturn(new TextNode("modifiedVast"))
976+
.willReturn(new TextNode("VAST"))
977+
.willReturn(new TextNode("updatedVast"));
978+
979+
// when
980+
target.cachePutObjects(
981+
asList(firstBidPutObject, secondBidPutObject, thirdBidPutObject),
982+
true,
983+
singleton("bidder1"),
984+
"account",
985+
"pbjs",
986+
timeout);
987+
988+
// then
989+
final BidPutObject modifiedFirstBidPutObject = firstBidPutObject.toBuilder()
990+
.bidid(null)
991+
.bidder(null)
992+
.timestamp(null)
993+
.key("account-sin1-high-ent")
994+
.value(new TextNode("modifiedVast"))
995+
.build();
996+
final BidPutObject modifiedSecondBidPutObject = secondBidPutObject.toBuilder()
997+
.bidid(null)
998+
.bidder(null)
999+
.timestamp(null)
1000+
.key("account-sin1-high-ent")
1001+
.build();
1002+
final BidPutObject modifiedThirdBidPutObject = thirdBidPutObject.toBuilder()
1003+
.bidid(null)
1004+
.bidder(null)
1005+
.timestamp(null)
1006+
.key("account-sin1-high-ent")
1007+
.value(new TextNode("updatedVast"))
1008+
.build();
1009+
1010+
assertThat(captureBidCacheRequest().getPuts())
1011+
.containsExactly(modifiedFirstBidPutObject, modifiedSecondBidPutObject, modifiedThirdBidPutObject);
1012+
}
1013+
8421014
private AuctionContext givenAuctionContext(UnaryOperator<Account.AccountBuilder> accountCustomizer,
8431015
UnaryOperator<BidRequest.BidRequestBuilder> bidRequestCustomizer) {
8441016

0 commit comments

Comments
 (0)