-
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
Max origin concurrent auctions #2743
Changes from all commits
f5ecbc0
6bc848d
7b1c3d7
62df3fa
e85160e
8cd5ad3
3d31b0e
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 |
---|---|---|
|
@@ -74,6 +74,11 @@ events.on(CONSTANTS.EVENTS.BID_ADJUSTMENT, function (bid) { | |
adjustBids(bid); | ||
}); | ||
|
||
const MAX_REQUESTS_PER_ORIGIN = 4; | ||
const outstandingRequests = {}; | ||
const sourceInfo = {}; | ||
const queuedCalls = []; | ||
|
||
/** | ||
* Creates new auction instance | ||
* | ||
|
@@ -176,26 +181,103 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels}) | |
} | ||
|
||
function callBids() { | ||
startAuctionTimer(); | ||
_auctionStatus = AUCTION_STARTED; | ||
_auctionStart = Date.now(); | ||
|
||
const auctionInit = { | ||
timestamp: _auctionStart, | ||
auctionId: _auctionId, | ||
timeout: _timeout | ||
}; | ||
events.emit(CONSTANTS.EVENTS.AUCTION_INIT, auctionInit); | ||
|
||
let bidRequests = adaptermanager.makeBidRequests(_adUnits, _auctionStart, _auctionId, _timeout, _labels); | ||
utils.logInfo(`Bids Requested for Auction with id: ${_auctionId}`, bidRequests); | ||
bidRequests.forEach(bidRequest => { | ||
addBidRequests(bidRequest); | ||
}); | ||
|
||
_auctionStatus = AUCTION_IN_PROGRESS; | ||
adaptermanager.callBids(_adUnits, bidRequests, addBidResponse.bind(this), done.bind(this)); | ||
}; | ||
let requests = {}; | ||
|
||
let call = { | ||
bidRequests, | ||
run: () => { | ||
startAuctionTimer(); | ||
|
||
_auctionStatus = AUCTION_IN_PROGRESS; | ||
|
||
const auctionInit = { | ||
timestamp: _auctionStart, | ||
auctionId: _auctionId, | ||
timeout: _timeout | ||
}; | ||
events.emit(CONSTANTS.EVENTS.AUCTION_INIT, auctionInit); | ||
|
||
adaptermanager.callBids(_adUnits, bidRequests, addBidResponse.bind(this), done.bind(this), { | ||
request(source, origin) { | ||
increment(outstandingRequests, origin); | ||
increment(requests, source); | ||
|
||
if (!sourceInfo[source]) { | ||
sourceInfo[source] = { | ||
SRA: true, | ||
origin | ||
}; | ||
} | ||
if (requests[source] > 1) { | ||
sourceInfo[source].SRA = false; | ||
} | ||
}, | ||
done(origin) { | ||
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. Should we rename this done to avoid confusion between auction done and this done ? 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 could, although I'm not sure it's a huge deal. I intentionally kept it as short as possible since it's an object property, so it won't be minified. |
||
outstandingRequests[origin]--; | ||
if (queuedCalls[0]) { | ||
if (runIfOriginHasCapacity(queuedCalls[0])) { | ||
queuedCalls.shift(); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
}; | ||
|
||
if (!runIfOriginHasCapacity(call)) { | ||
utils.logWarn('queueing auction due to limited endpoint capacity'); | ||
queuedCalls.push(call); | ||
} | ||
|
||
function runIfOriginHasCapacity(call) { | ||
let hasCapacity = true; | ||
|
||
let maxRequests = config.getConfig('maxRequestsPerOrigin') || MAX_REQUESTS_PER_ORIGIN; | ||
|
||
call.bidRequests.some(bidRequest => { | ||
let requests = 1; | ||
let source = (typeof bidRequest.src !== 'undefined' && bidRequest.src === CONSTANTS.S2S.SRC) ? 's2s' | ||
: bidRequest.bidderCode; | ||
// if we have no previous info on this source just let them through | ||
if (sourceInfo[source]) { | ||
if (sourceInfo[source].SRA === false) { | ||
// some bidders might use more than the MAX_REQUESTS_PER_ORIGIN in a single auction. In those cases | ||
// set their request count to MAX_REQUESTS_PER_ORIGIN so the auction isn't permanently queued waiting | ||
// for capacity for that bidder | ||
requests = Math.min(bidRequest.bids.length, maxRequests); | ||
} | ||
if (outstandingRequests[sourceInfo[source].origin] + requests > maxRequests) { | ||
hasCapacity = false; | ||
} | ||
} | ||
// return only used for terminating this .some() iteration early if it is determined we don't have capacity | ||
return !hasCapacity; | ||
}); | ||
|
||
if (hasCapacity) { | ||
call.run(); | ||
} | ||
|
||
return hasCapacity; | ||
} | ||
|
||
function increment(obj, prop) { | ||
if (typeof obj[prop] === 'undefined') { | ||
obj[prop] = 1 | ||
} else { | ||
obj[prop]++; | ||
} | ||
} | ||
} | ||
|
||
return { | ||
addBidReceived, | ||
|
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.
what's the magic behind 4? I thought modern browser was 6?
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.
On my specific test page there wasn't much difference with fast internet between 4 and 6 but there was a slight improvement on slow pages with 4 vs 6. I'm not sure why, but I decided it would be safer to go with that value; if other's test prove differently then we could change it down the line. It's also one of the reasons I made it configurable.