Skip to content

Commit 814c742

Browse files
authored
Process Stored Request/Imp IDs unique per account (prebid#488)
* Process Stored Request/Imp IDs unique per account * Process Stored Request/Imp IDs unique per account - update docs * Updated for AMP+Account * Clean the code * Update docs * Update docs * Small refactor * Add account support for CachingApplicationSettings * refactored after PR review * refactored after PR review - video fixed * Fixes after review
1 parent d335e78 commit 814c742

40 files changed

+1217
-631
lines changed

docs/config.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ metrics:
2424
settings:
2525
database:
2626
type: mysql
27-
stored-requests-query: SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%) UNION ALL SELECT impid, impData, 'imp' as dataType FROM stored_imps WHERE impid IN (%IMP_ID_LIST%)
28-
amp-stored-requests-query: SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%)
27+
stored-requests-query: SELECT accountId, reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%) UNION ALL SELECT accountId, impid, impData, 'imp' as dataType FROM stored_imps WHERE impid IN (%IMP_ID_LIST%)
28+
amp-stored-requests-query: SELECT accountId, reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%)
2929
stored-responses-query: SELECT resid, responseData FROM stored_responses WHERE resid IN (%RESPONSE_ID_LIST%)
3030
```
3131
If some property is missed in `prebid-config.yaml` application will look for it in `src/main/resources/application.yaml` file.

docs/developers/stored-requests.md

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ For example, assume the following `stored-requests/stored-request.json`:
137137
}
138138
```
139139

140-
Then an HTTP request like:
140+
Then HTTP request like:
141141

142142
```json
143143
{
@@ -178,8 +178,7 @@ Prebid Server does allow Stored BidRequests and Stored Imps in the same HTTP Req
178178
The Stored BidRequest will be applied first, and then the Stored Imps after.
179179

180180
**Beware**: Stored Request data will not be applied recursively.
181-
If a Stored BidRequest includes Imps with their own Stored Request IDs,
182-
then the data for those Stored Imps not be resolved.
181+
If a Stored BidRequest includes Imps with their own Stored Request IDs, then the data for those Stored Imps will not be resolved.
183182

184183
## Alternate backends
185184

@@ -193,13 +192,6 @@ For PostgreSQL:
193192
settings:
194193
database:
195194
type: postgres
196-
host: localhost
197-
port: 5432
198-
dbname: database-name
199-
user: username
200-
password: password
201-
stored-requests-query: SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%) UNION ALL SELECT impid, impData, 'imp' as dataType FROM stored_imps WHERE impid IN (%IMP_ID_LIST%)
202-
amp-stored-requests-query: SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%)
203195
```
204196

205197
For MySQL:
@@ -209,10 +201,11 @@ settings:
209201
type: mysql
210202
```
211203

212-
The select query columns of `stored-data-query` and `amp-stored-data-query` properties should correspond to the specific format:
213-
- first column: ID of stored data item
214-
- second column: value of stored data item
215-
- third column: type of stored data item. Can be `request` for stored requests or `imp` for stored impressions.
204+
The select query columns of `stored-requests-query` and `amp-stored-requests-query` properties should correspond to the specific format:
205+
- first column: account ID which is searched by.
206+
- second column: ID of stored data item which is searched by.
207+
- third column: value of stored data item.
208+
- forth column: type of stored data item. Can be `request` for stored requests or `imp` for stored impressions.
216209

217210
### HTTP backend
218211

@@ -261,8 +254,8 @@ settings:
261254
dbname: database-name
262255
user: username
263256
password: password
264-
stored-requests-query: SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%) UNION ALL SELECT impid, impData, 'imp' as dataType FROM stored_imps WHERE impid IN (%IMP_ID_LIST%)
265-
amp-stored-requests-query: SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%)
257+
stored-requests-query: SELECT accountId, reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%) UNION ALL SELECT accountId, impid, impData, 'imp' as dataType FROM stored_imps WHERE impid IN (%IMP_ID_LIST%)
258+
amp-stored-requests-query: SELECT accountId, reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%)
266259
http:
267260
endpoint: http://stored-requests.prebid.com
268261
amp-endpoint: http://stored-requests.prebid.com?amp=true

src/main/java/org/prebid/server/auction/AmpRequestFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public Future<AuctionContext> fromRequest(RoutingContext routingContext, long st
121121
*/
122122
private Future<Tuple2<BidRequest, List<String>>> createBidRequest(RoutingContext context, String tagId) {
123123
final List<String> errors = new ArrayList<>();
124-
return storedRequestProcessor.processAmpRequest(tagId)
124+
return storedRequestProcessor.processAmpRequest(context.request().getParam(ACCOUNT_REQUEST_PARAM), tagId)
125125
.map(bidRequest -> validateStoredBidRequest(tagId, bidRequest))
126126
.map(bidRequest -> fillExplicitParameters(bidRequest, context))
127127
.map(bidRequest -> overrideParameters(bidRequest, context.request(), errors))

src/main/java/org/prebid/server/auction/AuctionRequestFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ private BidRequest parseRequest(RoutingContext context, List<String> errors) {
253253
* updated by values derived from headers and other request attributes.
254254
*/
255255
private Future<BidRequest> updateBidRequest(RoutingContext context, BidRequest bidRequest) {
256-
return storedRequestProcessor.processStoredRequests(bidRequest)
256+
return storedRequestProcessor.processStoredRequests(accountIdFrom(bidRequest), bidRequest)
257257
.map(resolvedBidRequest -> fillImplicitParameters(resolvedBidRequest, context, timeoutResolver))
258258
.map(this::validateRequest)
259259
.map(interstitialProcessor::process);

src/main/java/org/prebid/server/auction/BidResponseCreator.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ private Future<BidResponse> cacheBidsAndCreateResponse(List<BidderResponse> bidd
222222
auctionContext,
223223
cacheInfo,
224224
eventsContext)
225-
.compose(cacheResult -> videoStoredDataResult(bidRequest.getImp(), auctionContext.getTimeout())
225+
.compose(cacheResult -> videoStoredDataResult(auctionContext)
226226
.map(videoStoredDataResult -> toBidResponse(
227227
bidderResponses,
228228
auctionContext,
@@ -698,9 +698,14 @@ private BidResponse toBidResponse(List<BidderResponse> bidderResponses,
698698
.build();
699699
}
700700

701-
private Future<VideoStoredDataResult> videoStoredDataResult(List<Imp> imps, Timeout timeout) {
701+
private Future<VideoStoredDataResult> videoStoredDataResult(AuctionContext auctionContext) {
702+
final List<Imp> imps = auctionContext.getBidRequest().getImp();
703+
final String accountId = auctionContext.getAccount().getId();
704+
final Timeout timeout = auctionContext.getTimeout();
705+
702706
final List<String> errors = new ArrayList<>();
703707
final List<Imp> storedVideoInjectableImps = new ArrayList<>();
708+
704709
for (Imp imp : imps) {
705710
try {
706711
if (checkEchoVideoAttrs(imp)) {
@@ -711,7 +716,7 @@ private Future<VideoStoredDataResult> videoStoredDataResult(List<Imp> imps, Time
711716
}
712717
}
713718

714-
return storedRequestProcessor.videoStoredDataResult(storedVideoInjectableImps, errors, timeout)
719+
return storedRequestProcessor.videoStoredDataResult(accountId, storedVideoInjectableImps, errors, timeout)
715720
.otherwise(throwable -> VideoStoredDataResult.of(Collections.emptyMap(),
716721
Collections.singletonList(throwable.getMessage())));
717722
}

src/main/java/org/prebid/server/auction/StoredRequestProcessor.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public StoredRequestProcessor(long defaultTimeout,
6666
* fetched jsons from source. In case any error happen during the process, returns failedFuture with
6767
* InvalidRequestException {@link InvalidRequestException} as cause.
6868
*/
69-
Future<BidRequest> processStoredRequests(BidRequest bidRequest) {
69+
Future<BidRequest> processStoredRequests(String accountId, BidRequest bidRequest) {
7070
final Map<BidRequest, String> bidRequestToStoredRequestId;
7171
final Map<Imp, String> impToStoredRequestId;
7272
try {
@@ -86,7 +86,7 @@ Future<BidRequest> processStoredRequests(BidRequest bidRequest) {
8686
}
8787

8888
final Future<StoredDataResult> storedDataFuture =
89-
applicationSettings.getStoredData(requestIds, impIds, timeout(bidRequest))
89+
applicationSettings.getStoredData(accountId, requestIds, impIds, timeout(bidRequest))
9090
.compose(storedDataResult -> updateMetrics(storedDataResult, requestIds, impIds));
9191

9292
return storedRequestsToBidRequest(storedDataFuture, bidRequest,
@@ -97,19 +97,20 @@ private Future<StoredDataResult> updateMetrics(StoredDataResult storedDataResult
9797
Set<String> impIds) {
9898
requestIds.forEach(
9999
id -> metrics.updateStoredRequestMetric(storedDataResult.getStoredIdToRequest().containsKey(id)));
100-
impIds.forEach(id -> metrics.updateStoredImpsMetric(storedDataResult.getStoredIdToImp().containsKey(id)));
100+
impIds.forEach(
101+
id -> metrics.updateStoredImpsMetric(storedDataResult.getStoredIdToImp().containsKey(id)));
101102

102103
return Future.succeededFuture(storedDataResult);
103104
}
104105

105106
/**
106107
* Fetches AMP request from the source.
107108
*/
108-
Future<BidRequest> processAmpRequest(String ampRequestId) {
109+
Future<BidRequest> processAmpRequest(String accountId, String ampRequestId) {
109110
final BidRequest bidRequest = BidRequest.builder().build();
110111
final Future<StoredDataResult> ampStoredDataFuture =
111112
applicationSettings.getAmpStoredData(
112-
Collections.singleton(ampRequestId), Collections.emptySet(), timeout(bidRequest))
113+
accountId, Collections.singleton(ampRequestId), Collections.emptySet(), timeout(bidRequest))
113114
.compose(storedDataResult -> updateMetrics(
114115
storedDataResult, Collections.singleton(ampRequestId), Collections.emptySet()));
115116

@@ -119,14 +120,15 @@ Future<BidRequest> processAmpRequest(String ampRequestId) {
119120
/**
120121
* Fetches stored request.video and map existing values to imp.id.
121122
*/
122-
Future<VideoStoredDataResult> videoStoredDataResult(List<Imp> imps, List<String> errors, Timeout timeout) {
123+
Future<VideoStoredDataResult> videoStoredDataResult(String accountId, List<Imp> imps, List<String> errors,
124+
Timeout timeout) {
123125
final Map<String, String> storedIdToImpId =
124126
mapStoredRequestHolderToStoredRequestId(imps, this::getStoredRequestFromImp)
125127
.entrySet().stream()
126128
.collect(Collectors.toMap(Map.Entry::getValue,
127129
impIdToStoredId -> impIdToStoredId.getKey().getId()));
128130

129-
return applicationSettings.getStoredData(Collections.emptySet(), storedIdToImpId.keySet(), timeout)
131+
return applicationSettings.getStoredData(accountId, Collections.emptySet(), storedIdToImpId.keySet(), timeout)
130132
.map(storedDataResult -> makeVideoStoredDataResult(storedDataResult, storedIdToImpId, errors));
131133
}
132134

src/main/java/org/prebid/server/auction/VideoRequestFactory.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package org.prebid.server.auction;
22

3+
import com.iab.openrtb.request.App;
34
import com.iab.openrtb.request.BidRequest;
45
import com.iab.openrtb.request.Device;
6+
import com.iab.openrtb.request.Publisher;
7+
import com.iab.openrtb.request.Site;
58
import com.iab.openrtb.request.video.BidRequestVideo;
69
import com.iab.openrtb.request.video.Pod;
710
import com.iab.openrtb.request.video.PodError;
@@ -10,13 +13,16 @@
1013
import io.vertx.core.buffer.Buffer;
1114
import io.vertx.ext.web.RoutingContext;
1215
import org.apache.commons.collections4.CollectionUtils;
16+
import org.apache.commons.lang3.ObjectUtils;
1317
import org.apache.commons.lang3.StringUtils;
1418
import org.prebid.server.auction.model.AuctionContext;
1519
import org.prebid.server.auction.model.WithPodErrors;
1620
import org.prebid.server.exception.InvalidRequestException;
1721
import org.prebid.server.json.DecodeException;
1822
import org.prebid.server.json.JacksonMapper;
1923
import org.prebid.server.metric.MetricName;
24+
import org.prebid.server.proto.openrtb.ext.request.ExtPublisher;
25+
import org.prebid.server.proto.openrtb.ext.request.ExtPublisherPrebid;
2026
import org.prebid.server.util.HttpUtil;
2127

2228
import java.util.ArrayList;
@@ -77,6 +83,38 @@ public Future<WithPodErrors<AuctionContext>> fromRequest(RoutingContext routingC
7783
.map(auctionContext -> WithPodErrors.of(auctionContext, bidRequestToPodError.getPodErrors())));
7884
}
7985

86+
/**
87+
* Extracts publisher id either from {@link BidRequestVideo}.app.publisher
88+
* or {@link BidRequestVideo}.site.publisher. If neither is present returns empty string.
89+
*/
90+
private String accountIdFrom(BidRequestVideo bidRequestVideo) {
91+
final App app = bidRequestVideo.getApp();
92+
final Publisher appPublisher = app != null ? app.getPublisher() : null;
93+
final Site site = bidRequestVideo.getSite();
94+
final Publisher sitePublisher = site != null ? site.getPublisher() : null;
95+
96+
final Publisher publisher = ObjectUtils.defaultIfNull(appPublisher, sitePublisher);
97+
final String publisherId = publisher != null ? resolvePublisherId(publisher) : null;
98+
return ObjectUtils.defaultIfNull(publisherId, StringUtils.EMPTY);
99+
}
100+
101+
/**
102+
* Resolves what value should be used as a publisher id - either taken from publisher.ext.parentAccount
103+
* or publisher.id in this respective priority.
104+
*/
105+
private String resolvePublisherId(Publisher publisher) {
106+
final String parentAccountId = parentAccountIdFromExtPublisher(publisher.getExt());
107+
return ObjectUtils.defaultIfNull(parentAccountId, publisher.getId());
108+
}
109+
110+
/**
111+
* Parses publisher.ext and returns parentAccount value from it. Returns null if any parsing error occurs.
112+
*/
113+
private String parentAccountIdFromExtPublisher(ExtPublisher extPublisher) {
114+
final ExtPublisherPrebid extPublisherPrebid = extPublisher != null ? extPublisher.getPrebid() : null;
115+
return extPublisherPrebid != null ? StringUtils.stripToNull(extPublisherPrebid.getParentAccount()) : null;
116+
}
117+
80118
/**
81119
* Parses request body to {@link BidRequestVideo}.
82120
* <p>
@@ -137,7 +175,8 @@ private Future<WithPodErrors<BidRequest>> createBidRequest(RoutingContext routin
137175
BidRequestVideo bidRequestVideo,
138176
String storedVideoId,
139177
Set<String> podConfigIds) {
140-
return storedRequestProcessor.processVideoRequest(storedVideoId, podConfigIds, bidRequestVideo)
178+
return storedRequestProcessor.processVideoRequest(accountIdFrom(bidRequestVideo), storedVideoId, podConfigIds,
179+
bidRequestVideo)
141180
.map(bidRequestToErrors -> fillImplicitParameters(routingContext, bidRequestToErrors))
142181
.map(this::validateRequest);
143182
}

src/main/java/org/prebid/server/auction/VideoStoredRequestProcessor.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import java.util.ArrayList;
4343
import java.util.Collections;
4444
import java.util.HashMap;
45-
import java.util.HashSet;
4645
import java.util.List;
4746
import java.util.Map;
4847
import java.util.Objects;
@@ -95,13 +94,15 @@ public VideoStoredRequestProcessor(ApplicationSettings applicationSettings, Vide
9594
/**
9695
* Fetches ParsedStoredDataResult&lt;BidRequestVideo, Imp&gt; from stored request.
9796
*/
98-
Future<WithPodErrors<BidRequest>> processVideoRequest(String storedBidRequestId, Set<String> podIds,
97+
Future<WithPodErrors<BidRequest>> processVideoRequest(String accountId, String storedBidRequestId,
98+
Set<String> podIds,
9999
BidRequestVideo receivedRequest) {
100-
final Set<String> storedRequestIds = new HashSet<>();
101-
if (StringUtils.isNotBlank(storedBidRequestId)) {
102-
storedRequestIds.add(storedBidRequestId);
103-
}
104-
return applicationSettings.getVideoStoredData(storedRequestIds, podIds, timeoutFactory.create(defaultTimeout))
100+
final Set<String> storedRequestIds = StringUtils.isNotBlank(storedBidRequestId)
101+
? Collections.singleton(storedBidRequestId)
102+
: Collections.emptySet();
103+
104+
return applicationSettings.getVideoStoredData(accountId, storedRequestIds, podIds,
105+
timeoutFactory.create(defaultTimeout))
105106
.compose(storedDataResult -> updateMetrics(storedDataResult, storedRequestIds, podIds))
106107
.map(storedData -> mergeToBidRequest(storedData, receivedRequest, storedBidRequestId))
107108
.recover(exception -> Future.failedFuture(new InvalidRequestException(

src/main/java/org/prebid/server/settings/ApplicationSettings.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,35 @@
2121
public interface ApplicationSettings {
2222

2323
/**
24-
* Returns {@link Account} info for given a accountId
24+
* Returns {@link Account} for the given account ID.
2525
*/
2626
Future<Account> getAccountById(String accountId, Timeout timeout);
2727

2828
/**
29-
* Returns AddUnitConfig info for a given adUnitConfigId
29+
* Returns configuration for the given adUnit config ID.
3030
*/
3131
Future<String> getAdUnitConfigById(String adUnitConfigId, Timeout timeout);
3232

3333
/**
34-
* Fetches stored requests and imps
34+
* Fetches stored requests and imps by IDs.
3535
*/
36-
Future<StoredDataResult> getStoredData(Set<String> requestIds, Set<String> impIds, Timeout timeout);
36+
Future<StoredDataResult> getStoredData(String accountId, Set<String> requestIds, Set<String> impIds,
37+
Timeout timeout);
3738

3839
/**
39-
* Fetches stored response
40+
* Fetches AMP stored requests and imps by IDs.
4041
*/
41-
Future<StoredResponseDataResult> getStoredResponses(Set<String> responseIds, Timeout timeout);
42+
Future<StoredDataResult> getAmpStoredData(String accountId, Set<String> requestIds, Set<String> impIds,
43+
Timeout timeout);
4244

4345
/**
44-
* Fetches AMP stored requests and imps
46+
* Fetches Video stored requests and imps by IDs.
4547
*/
46-
Future<StoredDataResult> getAmpStoredData(Set<String> requestIds, Set<String> impIds, Timeout timeout);
48+
Future<StoredDataResult> getVideoStoredData(String accountId, Set<String> requestIds, Set<String> impIds,
49+
Timeout timeout);
4750

4851
/**
49-
* Fetches Video stored requests and imps
52+
* Fetches stored response by IDs.
5053
*/
51-
Future<StoredDataResult> getVideoStoredData(Set<String> requestIds, Set<String> impIds, Timeout timeout);
54+
Future<StoredResponseDataResult> getStoredResponses(Set<String> responseIds, Timeout timeout);
5255
}

0 commit comments

Comments
 (0)