Skip to content

Commit 297bb48

Browse files
authored
Prebid core: allow configurable TTL buffer (prebid#9136)
1 parent cc3f01d commit 297bb48

File tree

6 files changed

+72
-6
lines changed

6 files changed

+72
-6
lines changed

src/auction.js

+5
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ export const callPrebidCache = hook('async', function(auctionInstance, bidRespon
666666
*/
667667
function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionManager.index} = {}) {
668668
const bidderRequest = index.getBidderRequest(bidResponse);
669+
const adUnit = index.getAdUnit(bidResponse);
669670
const start = (bidderRequest && bidderRequest.start) || bidResponse.requestTimestamp;
670671

671672
Object.assign(bidResponse, {
@@ -676,6 +677,10 @@ function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionMa
676677
adUnitCode
677678
});
678679

680+
if (adUnit?.ttlBuffer != null) {
681+
bidResponse.ttlBuffer = adUnit.ttlBuffer;
682+
}
683+
679684
bidResponse.timeToRespond = bidResponse.responseTimestamp - bidResponse.requestTimestamp;
680685
}
681686

src/prebid.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -622,15 +622,15 @@ $$PREBID_GLOBAL$$.removeAdUnit = function (adUnitCode) {
622622
* @alias module:pbjs.requestBids
623623
*/
624624
$$PREBID_GLOBAL$$.requestBids = (function() {
625-
const delegate = hook('sync', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ortb2, metrics } = {}) {
625+
const delegate = hook('sync', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2, metrics } = {}) {
626626
events.emit(REQUEST_BIDS);
627627
const cbTimeout = timeout || config.getConfig('bidderTimeout');
628628
logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments);
629629
const ortb2Fragments = {
630630
global: mergeDeep({}, config.getAnyConfig('ortb2') || {}, ortb2 || {}),
631631
bidder: Object.fromEntries(Object.entries(config.getBidderConfig()).map(([bidder, cfg]) => [bidder, cfg.ortb2]).filter(([_, ortb2]) => ortb2 != null))
632632
}
633-
return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics});
633+
return startAuction({bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ttlBuffer, ortb2Fragments, metrics});
634634
}, 'requestBids');
635635

636636
return wrapHook(delegate, function requestBids(req = {}) {
@@ -646,7 +646,7 @@ $$PREBID_GLOBAL$$.requestBids = (function() {
646646
});
647647
})();
648648

649-
export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) {
649+
export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, ttlBuffer, adUnitCodes, labels, auctionId, ortb2Fragments, metrics } = {}) {
650650
const s2sBidders = getS2SBidderSet(config.getConfig('s2sConfig') || []);
651651
adUnits = useMetrics(metrics).measureTime('requestBids.validate', () => checkAdUnitSetup(adUnits));
652652

@@ -688,6 +688,9 @@ export const startAuction = hook('sync', function ({ bidsBackHandler, timeout: c
688688

689689
const tid = adUnit.ortb2Imp?.ext?.tid || generateUUID();
690690
adUnit.transactionId = tid;
691+
if (ttlBuffer != null && !adUnit.hasOwnProperty('ttlBuffer')) {
692+
adUnit.ttlBuffer = ttlBuffer;
693+
}
691694
// Populate ortb2Imp.ext.tid with transactionId. Specifying a transaction ID per item in the ortb impression array, lets multiple transaction IDs be transmitted in a single bid request.
692695
deepSetValue(adUnit, 'ortb2Imp.ext.tid', tid);
693696

src/targeting.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,15 @@ import CONSTANTS from './constants.json';
2828
var pbTargetingKeys = [];
2929

3030
const MAX_DFP_KEYLENGTH = 20;
31-
const TTL_BUFFER = 1000;
31+
let DEFAULT_TTL_BUFFER = 1;
32+
33+
config.getConfig('ttlBuffer', (cfg) => {
34+
if (typeof cfg.ttlBuffer === 'number') {
35+
DEFAULT_TTL_BUFFER = cfg.ttlBuffer;
36+
} else {
37+
logError('Invalid value for ttlBuffer', cfg.ttlBuffer);
38+
}
39+
})
3240

3341
const CFG_ALLOW_TARGETING_KEYS = `targetingControls.allowTargetingKeys`;
3442
const CFG_ADD_TARGETING_KEYS = `targetingControls.addTargetingKeys`;
@@ -39,7 +47,7 @@ export const TARGETING_KEYS = Object.keys(CONSTANTS.TARGETING_KEYS).map(
3947
);
4048

4149
// return unexpired bids
42-
const isBidNotExpired = (bid) => (bid.responseTimestamp + bid.ttl * 1000 - TTL_BUFFER) > timestamp();
50+
const isBidNotExpired = (bid) => (bid.responseTimestamp + (bid.ttl - (bid.hasOwnProperty('ttlBuffer') ? bid.ttlBuffer : DEFAULT_TTL_BUFFER)) * 1000) > timestamp();
4351

4452
// return bids whose status is not set. Winning bids can only have a status of `rendered`.
4553
const isUnusedBid = (bid) => bid && ((bid.status && !includes([CONSTANTS.BID_STATUS.RENDERED], bid.status)) || !bid.status);

test/spec/auctionmanager_spec.js

+6
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,12 @@ describe('auctionmanager.js', function () {
955955
const addedBid = find(auction.getBidsReceived(), bid => bid.adUnitCode == ADUNIT_CODE);
956956
assert.equal(addedBid.renderer.url, 'renderer.js');
957957
});
958+
959+
it('sets bidResponse.ttlBuffer from adUnit.ttlBuffer', () => {
960+
adUnits[0].ttlBuffer = 0;
961+
auction.callBids();
962+
expect(auction.getBidsReceived()[0].ttlBuffer).to.eql(0);
963+
});
958964
});
959965

960966
describe('when auction timeout is 20', function () {

test/spec/unit/core/targeting_spec.js

+34
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,40 @@ describe('targeting tests', function () {
269269
bidCacheFilterFunction = undef;
270270
});
271271

272+
describe('isBidNotExpired', () => {
273+
let clock;
274+
beforeEach(() => {
275+
clock = sandbox.useFakeTimers(0);
276+
});
277+
278+
Object.entries({
279+
'bid.ttlBuffer': (bid, ttlBuffer) => {
280+
bid.ttlBuffer = ttlBuffer
281+
},
282+
'setConfig({ttlBuffer})': (_, ttlBuffer) => {
283+
config.setConfig({ttlBuffer})
284+
},
285+
}).forEach(([t, setup]) => {
286+
describe(`respects ${t}`, () => {
287+
[0, 2].forEach(ttlBuffer => {
288+
it(`when ttlBuffer is ${ttlBuffer}`, () => {
289+
const bid = {
290+
responseTimestamp: 0,
291+
ttl: 10,
292+
}
293+
setup(bid, ttlBuffer);
294+
295+
expect(filters.isBidNotExpired(bid)).to.be.true;
296+
clock.tick((bid.ttl - ttlBuffer) * 1000 - 100);
297+
expect(filters.isBidNotExpired(bid)).to.be.true;
298+
clock.tick(101);
299+
expect(filters.isBidNotExpired(bid)).to.be.false;
300+
});
301+
});
302+
});
303+
});
304+
});
305+
272306
describe('getAllTargeting', function () {
273307
let amBidsReceivedStub;
274308
let amGetAdUnitsStub;

test/spec/unit/pbjs_api_spec.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -1459,7 +1459,7 @@ describe('Unit: Prebid Module', function () {
14591459

14601460
describe('requestBids', function () {
14611461
let logMessageSpy;
1462-
let makeRequestsStub;
1462+
let makeRequestsStub, createAuctionStub;
14631463
let adUnits;
14641464
let clock;
14651465
before(function () {
@@ -1670,6 +1670,16 @@ describe('Unit: Prebid Module', function () {
16701670
})
16711671
})
16721672
})
1673+
1674+
it('should transfer ttlBuffer to adUnit.ttlBuffer', () => {
1675+
$$PREBID_GLOBAL$$.requestBids({
1676+
ttlBuffer: 123,
1677+
adUnits: [adUnits[0], {...adUnits[0], ttlBuffer: 0}]
1678+
});
1679+
sinon.assert.calledWithMatch(auctionModule.newAuction, {
1680+
adUnits: sinon.match((units) => units[0].ttlBuffer === 123 && units[1].ttlBuffer === 0)
1681+
})
1682+
});
16731683
})
16741684

16751685
describe('requestBids', function () {

0 commit comments

Comments
 (0)