-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix timeout issues #699 #700
Changes from all commits
03d050a
0541c63
e47efec
5eaa3a6
c73cbd6
fd9a6e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ var objectType_function = 'function'; | |
var externalCallbackByAdUnitArr = []; | ||
var externalCallbackArr = []; | ||
var externalOneTimeCallback = null; | ||
var externalOneTimeCallbackTimer = false; | ||
var _granularity = CONSTANTS.GRANULARITY_OPTIONS.MEDIUM; | ||
var defaultBidderSettingsMap = {}; | ||
|
||
|
@@ -40,29 +41,27 @@ function getBidders(bid) { | |
return bid.bidder; | ||
} | ||
|
||
function bidsBackAdUnit(adUnitCode) { | ||
let requested = $$PREBID_GLOBAL$$.adUnits.find(unit => unit.code === adUnitCode); | ||
if (requested) {requested = requested.bids.length;} | ||
const received = $$PREBID_GLOBAL$$._bidsReceived.filter(bid => bid.adUnitCode === adUnitCode).length; | ||
return requested === received; | ||
} | ||
|
||
function add(a, b) { | ||
return a + b; | ||
} | ||
|
||
function bidsBackAll() { | ||
const requested = $$PREBID_GLOBAL$$._bidsRequested.map(bidSet => bidSet.bids.length).reduce(add, 0); | ||
const received = $$PREBID_GLOBAL$$._bidsReceived.length; | ||
function bidsBack(adUnitCodes) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my testing this is called twice from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm in favor of combining the two There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't see this issue with both zero values... But I'll look for a fix in received, which is the culprit in the case of two auctions (the second time the requested isn't filtered correctly). |
||
adUnitCodes = adUnitCodes || $$PREBID_GLOBAL$$._adUnitCodes; | ||
const requested = $$PREBID_GLOBAL$$._bidsRequested.map(bidSet => { | ||
return bidSet.bids.filter(bid => adUnitCodes.includes(bid.placementCode)).length; | ||
}).reduce(add, 0); | ||
const received = $$PREBID_GLOBAL$$._bidsReceived.filter(bid => adUnitCodes.includes(bid.adUnitCode)).length; | ||
return requested === received; | ||
} | ||
|
||
exports.bidsBackAll = function() { | ||
return bidsBackAll(); | ||
exports.bidsBack = function() { | ||
return bidsBack(); | ||
}; | ||
|
||
function getBidSetForBidder(bidder) { | ||
return $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === bidder) || { start: null, requestId: null }; | ||
function getBidSetForBidder(bidder, adUnitCode) { | ||
return $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => { | ||
return bidSet.bids.filter(bid => bid.bidder === bidder && bid.placementCode === adUnitCode).length > 0; | ||
}) || { start: null, requestId: null }; | ||
} | ||
|
||
/* | ||
|
@@ -71,10 +70,11 @@ function getBidSetForBidder(bidder) { | |
exports.addBidResponse = function (adUnitCode, bid) { | ||
if (bid) { | ||
|
||
const bidSet = getBidSetForBidder(bid.bidderCode, adUnitCode); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be expressed as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! |
||
Object.assign(bid, { | ||
requestId: getBidSetForBidder(bid.bidderCode).requestId, | ||
requestId: bidSet.requestId, | ||
responseTimestamp: timestamp(), | ||
requestTimestamp: getBidSetForBidder(bid.bidderCode).start, | ||
requestTimestamp: bidSet.start, | ||
cpm: bid.cpm || 0, | ||
bidder: bid.bidderCode, | ||
adUnitCode | ||
|
@@ -83,9 +83,7 @@ exports.addBidResponse = function (adUnitCode, bid) { | |
bid.timeToRespond = bid.responseTimestamp - bid.requestTimestamp; | ||
|
||
if (bid.timeToRespond > $$PREBID_GLOBAL$$.cbTimeout + $$PREBID_GLOBAL$$.timeoutBuffer) { | ||
const timedOut = true; | ||
|
||
this.executeCallback(timedOut); | ||
this.executeCallback(true); | ||
} | ||
|
||
//emit the bidAdjustment event before bidResponse, so bid response has the adjusted bid value | ||
|
@@ -117,11 +115,11 @@ exports.addBidResponse = function (adUnitCode, bid) { | |
$$PREBID_GLOBAL$$._bidsReceived.push(bid); | ||
} | ||
|
||
if (bid && bid.adUnitCode && bidsBackAdUnit(bid.adUnitCode)) { | ||
if (bid && bid.adUnitCode && bidsBack([bid.adUnitCode])) { | ||
triggerAdUnitCallbacks(bid.adUnitCode); | ||
} | ||
|
||
if (bidsBackAll()) { | ||
if (bidsBack()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As noted above this can evaluate to true when |
||
this.executeCallback(); | ||
} | ||
}; | ||
|
@@ -222,6 +220,11 @@ exports.registerDefaultBidderSetting = function (bidderCode, defaultSetting) { | |
}; | ||
|
||
exports.executeCallback = function (timedOut) { | ||
// if there's still a timeout running, clear it now | ||
if (!timedOut && externalOneTimeCallbackTimer) { | ||
clearTimeout(externalOneTimeCallbackTimer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great catch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in #735 |
||
} | ||
|
||
if (externalCallbackArr.called !== true) { | ||
processCallbacks(externalCallbackArr); | ||
externalCallbackArr.called = true; | ||
|
@@ -242,6 +245,7 @@ exports.executeCallback = function (timedOut) { | |
} | ||
finally { | ||
externalOneTimeCallback = null; | ||
externalOneTimeCallbackTimer = false; | ||
$$PREBID_GLOBAL$$.clearAuction(); | ||
} | ||
} | ||
|
@@ -290,10 +294,12 @@ function groupByPlacement(prev, item, idx, arr) { | |
|
||
/** | ||
* Add a one time callback, that is discarded after it is called | ||
* @param {Function} callback [description] | ||
* @param {Function} callback | ||
* @param timer Timer to clear if callback is triggered before timer time's out | ||
*/ | ||
exports.addOneTimeCallback = function (callback) { | ||
exports.addOneTimeCallback = function (callback, timer) { | ||
externalOneTimeCallback = callback; | ||
externalOneTimeCallbackTimer = timer; | ||
}; | ||
|
||
exports.addCallback = function (id, callback, cbEvent) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ var eventValidators = { | |
|
||
$$PREBID_GLOBAL$$._bidsRequested = []; | ||
$$PREBID_GLOBAL$$._bidsReceived = []; | ||
$$PREBID_GLOBAL$$._adUnitCodes = []; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should avoid another primary data structure here and consider There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue here is that you can't know what adUnits are currently used in the current auction... But maybe that's because I've got rid of |
||
$$PREBID_GLOBAL$$._winningBids = []; | ||
$$PREBID_GLOBAL$$._adsReceived = []; | ||
$$PREBID_GLOBAL$$._sendAllBids = false; | ||
|
@@ -262,29 +263,22 @@ function getAllTargeting() { | |
return targeting; | ||
} | ||
|
||
function markComplete(adObject) { | ||
$$PREBID_GLOBAL$$._bidsRequested.filter(request => request.requestId === adObject.requestId) | ||
.forEach(request => request.bids.filter(bid => bid.placementCode === adObject.adUnitCode) | ||
.forEach(bid => bid.complete = true)); | ||
|
||
$$PREBID_GLOBAL$$._bidsReceived.filter(bid => { | ||
return bid.requestId === adObject.requestId && bid.adUnitCode === adObject.adUnitCode; | ||
}).forEach(bid => bid.complete = true); | ||
} | ||
|
||
function removeComplete() { | ||
function removePreviousBids(adUnitCode) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This raises the question of determining when bids are no longer valid. In As noted here and here and with this PR, the approach results in some unexpected "old" bids. However consider the case that there is nothing invalid about these bids necessarily, and including them in auctions may be desirable. For example, take a given placement auction where the highest bid is $5. As it happens the ad server fills with it's own demand. A subsequent request for bids for the placement returns a winner of $4. The "old" $5 bid is still a valid bid as far as the bidder is concerned. Why should we exclude the bid from the current outgoing auction? We are already throwing out some bids we perhaps shouldn't. Consider a case where Prebid demand fills a placement. The winner was a $10 bid, with a $5 bid behind it. A second request for bids goes out with a winner of $2. In this case we currently |
||
let requests = $$PREBID_GLOBAL$$._bidsRequested; | ||
let responses = $$PREBID_GLOBAL$$._bidsReceived; | ||
|
||
requests.map(request => request.bids | ||
.filter(bid => bid.complete)) | ||
.forEach(request => requests.splice(requests.indexOf(request), 1)); | ||
|
||
responses.filter(bid => bid.complete).forEach(bid => responses.splice(responses.indexOf(bid), 1)); | ||
requests.filter(request => { | ||
request.bids.filter(bid => { | ||
// bid has the placementCode, remove it | ||
if (bid.placementCode === adUnitCode) { | ||
return request.bids.splice(request.bids.indexOf(bid), 1); | ||
} | ||
}); | ||
// if there's no more bids, then the request can be removed | ||
return request.bids.length === 0; | ||
}).forEach(request => requests.splice(requests.indexOf(request), 1)); | ||
|
||
// also remove bids that have an empty or error status so known as not pending for render | ||
responses.filter(bid => bid.getStatusCode && bid.getStatusCode() === 2) | ||
.forEach(bid => responses.splice(responses.indexOf(bid), 1)); | ||
responses.filter(bid => bid.placementCode === adUnitCode).forEach(bid => responses.splice(responses.indexOf(bid), 1)); | ||
} | ||
|
||
////////////////////////////////// | ||
|
@@ -427,7 +421,7 @@ $$PREBID_GLOBAL$$.setTargetingForGPTAsync = function () { | |
*/ | ||
$$PREBID_GLOBAL$$.allBidsAvailable = function () { | ||
utils.logInfo('Invoking $$PREBID_GLOBAL$$.allBidsAvailable', arguments); | ||
return bidmanager.bidsBackAll(); | ||
return bidmanager.bidsBack(); | ||
}; | ||
|
||
/** | ||
|
@@ -449,8 +443,6 @@ $$PREBID_GLOBAL$$.renderAd = function (doc, id) { | |
//emit 'bid won' event here | ||
events.emit(BID_WON, adObject); | ||
|
||
// mark bid requests and responses for this placement in this auction as "complete" | ||
markComplete(adObject); | ||
var height = adObject.height; | ||
var width = adObject.width; | ||
var url = adObject.adUrl; | ||
|
@@ -526,9 +518,10 @@ $$PREBID_GLOBAL$$.clearAuction = function() { | |
$$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, adUnitCodes }) { | ||
const cbTimeout = $$PREBID_GLOBAL$$.cbTimeout = timeout || $$PREBID_GLOBAL$$.bidderTimeout; | ||
adUnits = adUnits || $$PREBID_GLOBAL$$.adUnits; | ||
adUnitCodes = adUnitCodes || []; | ||
|
||
// if specific adUnitCodes filter adUnits for those codes | ||
if (adUnitCodes && adUnitCodes.length) { | ||
if (adUnitCodes.length) { | ||
adUnits = adUnits.filter(adUnit => adUnitCodes.includes(adUnit.code)); | ||
} | ||
|
||
|
@@ -543,30 +536,33 @@ $$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, a | |
|
||
if (auctionRunning) { | ||
bidRequestQueue.push(() => { | ||
$$PREBID_GLOBAL$$.requestBids({ bidsBackHandler, cbTimeout, adUnits }); | ||
$$PREBID_GLOBAL$$.requestBids({ bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes }); | ||
}); | ||
return; | ||
} else { | ||
auctionRunning = true; | ||
removeComplete(); | ||
} | ||
|
||
if (typeof bidsBackHandler === objectType_function) { | ||
bidmanager.addOneTimeCallback(bidsBackHandler); | ||
auctionRunning = true; | ||
for (let i = 0; i < adUnitCodes.length; i++) { | ||
removePreviousBids(adUnitCodes[i]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As noted above we should avoid promoting |
||
} | ||
$$PREBID_GLOBAL$$._adUnitCodes = adUnitCodes; | ||
|
||
utils.logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments); | ||
|
||
if (!adUnits || adUnits.length === 0) { | ||
utils.logMessage('No adUnits configured. No bids requested.'); | ||
if (typeof bidsBackHandler === objectType_function) { | ||
bidmanager.addOneTimeCallback(bidsBackHandler); | ||
} | ||
bidmanager.executeCallback(); | ||
return; | ||
} | ||
|
||
//set timeout for all bids | ||
const timedOut = true; | ||
const timeoutCallback = bidmanager.executeCallback.bind(bidmanager, timedOut); | ||
setTimeout(timeoutCallback, cbTimeout); | ||
const timeoutCallback = bidmanager.executeCallback.bind(bidmanager, true); | ||
const timer = setTimeout(timeoutCallback, cbTimeout); | ||
if (typeof bidsBackHandler === objectType_function) { | ||
bidmanager.addOneTimeCallback(bidsBackHandler, timer); | ||
} | ||
|
||
adaptermanager.callBids({ adUnits, adUnitCodes, cbTimeout }); | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok for now, though I think we could consider a
callbackHandler
object withcallback
andtimer
function properties andexternalCallback...
array properties.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've fixed this in #735