Skip to content

Commit 7e41aa0

Browse files
Add useFetchDataRate for Price Floors (#3486)
1 parent 7157ed0 commit 7e41aa0

9 files changed

Lines changed: 478 additions & 145 deletions

File tree

src/main/java/org/prebid/server/floors/BasicPriceFloorProcessor.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.Collections;
3737
import java.util.List;
3838
import java.util.Objects;
39+
import java.util.Optional;
3940
import java.util.concurrent.ThreadLocalRandom;
4041

4142
public class BasicPriceFloorProcessor implements PriceFloorProcessor {
@@ -45,6 +46,7 @@ public class BasicPriceFloorProcessor implements PriceFloorProcessor {
4546

4647
private static final int SKIP_RATE_MIN = 0;
4748
private static final int SKIP_RATE_MAX = 100;
49+
private static final int USE_FETCH_DATA_RATE_MAX = 100;
4850
private static final int MODEL_WEIGHT_MAX_VALUE = 100;
4951
private static final int MODEL_WEIGHT_MIN_VALUE = 1;
5052

@@ -126,7 +128,7 @@ private PriceFloorRules resolveFloors(Account account, BidRequest bidRequest, Li
126128
final FetchResult fetchResult = floorFetcher.fetch(account);
127129
final FetchStatus fetchStatus = ObjectUtil.getIfNotNull(fetchResult, FetchResult::getFetchStatus);
128130

129-
if (shouldUseDynamicData(account) && fetchResult != null && fetchStatus == FetchStatus.success) {
131+
if (fetchResult != null && fetchStatus == FetchStatus.success && shouldUseDynamicData(account, fetchResult)) {
130132
final PriceFloorRules mergedFloors = mergeFloors(requestFloors, fetchResult.getRulesData());
131133
return createFloorsFrom(mergedFloors, fetchStatus, PriceFloorLocation.fetch);
132134
}
@@ -147,13 +149,20 @@ private PriceFloorRules resolveFloors(Account account, BidRequest bidRequest, Li
147149
return createFloorsFrom(null, fetchStatus, PriceFloorLocation.noData);
148150
}
149151

150-
private static boolean shouldUseDynamicData(Account account) {
151-
final AccountAuctionConfig auctionConfig = ObjectUtil.getIfNotNull(account, Account::getAuction);
152-
final AccountPriceFloorsConfig floorsConfig =
153-
ObjectUtil.getIfNotNull(auctionConfig, AccountAuctionConfig::getPriceFloors);
152+
private static boolean shouldUseDynamicData(Account account, FetchResult fetchResult) {
153+
final boolean isUsingDynamicDataAllowed = Optional.ofNullable(account)
154+
.map(Account::getAuction)
155+
.map(AccountAuctionConfig::getPriceFloors)
156+
.map(AccountPriceFloorsConfig::getUseDynamicData)
157+
.map(BooleanUtils::isNotFalse)
158+
.orElse(true);
154159

155-
return BooleanUtils.isNotFalse(
156-
ObjectUtil.getIfNotNull(floorsConfig, AccountPriceFloorsConfig::getUseDynamicData));
160+
final boolean shouldUseDynamicData = Optional.ofNullable(fetchResult.getRulesData())
161+
.map(PriceFloorData::getUseFetchDataRate)
162+
.map(rate -> ThreadLocalRandom.current().nextInt(USE_FETCH_DATA_RATE_MAX) < rate)
163+
.orElse(true);
164+
165+
return isUsingDynamicDataAllowed && shouldUseDynamicData;
157166
}
158167

159168
private PriceFloorRules mergeFloors(PriceFloorRules requestFloors,

src/main/java/org/prebid/server/floors/PriceFloorRulesValidator.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class PriceFloorRulesValidator {
1717
private static final int MODEL_WEIGHT_MIN_VALUE = 1;
1818
private static final int SKIP_RATE_MIN = 0;
1919
private static final int SKIP_RATE_MAX = 100;
20+
private static final int USE_FETCH_DATA_RATE_MIN = 0;
21+
private static final int USE_FETCH_DATA_RATE_MAX = 100;
2022

2123
private PriceFloorRulesValidator() {
2224
}
@@ -48,6 +50,14 @@ public static void validateRulesData(PriceFloorData priceFloorData, Integer maxR
4850
"Price floor data skipRate must be in range(0-100), but was " + dataSkipRate);
4951
}
5052

53+
final Integer useFetchDataRate = priceFloorData.getUseFetchDataRate();
54+
if (useFetchDataRate != null
55+
&& (useFetchDataRate < USE_FETCH_DATA_RATE_MIN || useFetchDataRate > USE_FETCH_DATA_RATE_MAX)) {
56+
57+
throw new PreBidException(
58+
"Price floor data useFetchDataRate must be in range(0-100), but was " + useFetchDataRate);
59+
}
60+
5161
if (CollectionUtils.isEmpty(priceFloorData.getModelGroups())) {
5262
throw new PreBidException("Price floor rules should contain at least one model group");
5363
}

src/main/java/org/prebid/server/floors/model/PriceFloorData.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ public class PriceFloorData {
1818
@JsonProperty("skipRate")
1919
Integer skipRate;
2020

21+
@JsonProperty("useFetchDataRate")
22+
Integer useFetchDataRate;
23+
2124
@JsonProperty("floorsSchemaVersion")
2225
String floorsSchemaVersion;
2326

src/test/groovy/org/prebid/server/functional/model/pricefloors/PriceFloorData.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class PriceFloorData implements ResponseModel {
1616
String floorProvider
1717
Currency currency
1818
Integer skipRate
19+
Integer useFetchDataRate
1920
String floorsSchemaVersion
2021
Integer modelTimestamp
2122
List<ModelGroup> modelGroups

src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsBaseSpec.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ abstract class PriceFloorsBaseSpec extends BaseSpec {
3737
public static final Map<String, String> FLOORS_CONFIG = ["price-floors.enabled" : "true",
3838
"settings.default-account-config": encode(defaultAccountConfigSettings)]
3939

40-
protected static final String basicFetchUrl = networkServiceContainer.rootUri + FloorsProvider.FLOORS_ENDPOINT
41-
protected static final FloorsProvider floorsProvider = new FloorsProvider(networkServiceContainer)
40+
protected static final String BASIC_FETCH_URL = networkServiceContainer.rootUri + FloorsProvider.FLOORS_ENDPOINT
4241
protected static final int MAX_MODEL_WEIGHT = 100
4342

4443
private static final int DEFAULT_MODEL_WEIGHT = 1
4544
private static final int CURRENCY_CONVERSION_PRECISION = 3
4645
private static final int FLOOR_VALUE_PRECISION = 4
4746

47+
protected static final FloorsProvider floorsProvider = new FloorsProvider(networkServiceContainer)
4848
protected final PrebidServerService floorsPbsService = pbsServiceFactory.getService(FLOORS_CONFIG + GENERIC_ALIAS_CONFIG)
4949

5050
def setupSpec() {
@@ -69,7 +69,7 @@ abstract class PriceFloorsBaseSpec extends BaseSpec {
6969

7070
protected static Account getAccountWithEnabledFetch(String accountId) {
7171
def priceFloors = new AccountPriceFloorsConfig(enabled: true,
72-
fetch: new PriceFloorsFetch(url: basicFetchUrl + accountId, enabled: true))
72+
fetch: new PriceFloorsFetch(url: BASIC_FETCH_URL + accountId, enabled: true))
7373
def accountConfig = new AccountConfig(auction: new AccountAuctionConfig(priceFloors: priceFloors))
7474
new Account(uuid: accountId, config: accountConfig)
7575
}

src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsCurrencySpec.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ class PriceFloorsCurrencySpec extends PriceFloorsBaseSpec {
243243
def account = getAccountWithEnabledFetch(bidRequest.accountId).tap {
244244
config.auction.priceFloors.fetch.enabled = priceFloors
245245
config.auction.priceFloorsSnakeCase = new AccountPriceFloorsConfig(enabled: true,
246-
fetch: new PriceFloorsFetch(url: basicFetchUrl + bidRequest.accountId, enabled: priceFloorsSnakeCase))
246+
fetch: new PriceFloorsFetch(url: BASIC_FETCH_URL + bidRequest.accountId, enabled: priceFloorsSnakeCase))
247247
}
248248
accountDao.save(account)
249249

0 commit comments

Comments
 (0)