-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New module: Shaping rules #14079
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
base: master
Are you sure you want to change the base?
New module: Shaping rules #14079
Conversation
42e6941 to
1b2ce0f
Compare
|
Tread carefully! This PR adds 1 linter error (possibly disabled through directives):
|
1 similar comment
|
Tread carefully! This PR adds 1 linter error (possibly disabled through directives):
|
Pull Request Test Coverage Report for Build 20305964562Details
💛 - Coveralls |
src/adapterManager.ts
Outdated
| const getTid = tidFactory(); | ||
|
|
||
| const mergeBidderFpd = (() => { | ||
| const fpdCache: Record<BidderCode, any> = {}; |
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.
this type is not correct, so why specify it? any is better.
src/adapterManager.ts
Outdated
| const mergeBidderFpd = (() => { | ||
| const fpdCache: Record<BidderCode, any> = {}; | ||
| return function(auctionId: string, bidderCode: BidderCode, s2sActivityParams?) { | ||
| const cacheKey = bidderCode + (s2sActivityParams != null ? s2sActivityParams[ACTIVITY_PARAM_S2S_NAME] : ''); |
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.
Simple string concat is risky here, I could have bidders a, ab and an s2s named b.
src/adapterManager.ts
Outdated
| .filter(uniques) | ||
| .forEach(incrementAuctionsCounter); | ||
|
|
||
| let {[PARTITIONS.CLIENT]: clientBidders, [PARTITIONS.SERVER]: serverBidders} = partitionBidders(adUnits, _s2sConfigs); |
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 think this wouldn't give the same result now that it happens before the filtering.
modules/rules/index.ts
Outdated
|
|
||
| export function evaluateSchema(func, args, context) { | ||
| switch (func) { | ||
| case 'percent': |
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.
An old fashioned map would be more readable (and less bug -prone) than a switch IMO
test/spec/modules/rules_spec.js
Outdated
| // Verify that excluded bidder is not allowed for processed-auction | ||
| expect(isActivityAllowed(ACTIVITY_ADD_BID_RESPONSE, activityParams(MODULE_TYPE_BIDDER, 'bidder3', {}))).to.eql(false); | ||
| // Verify that non-excluded bidder is allowed for processed-auction | ||
| expect(isActivityAllowed(ACTIVITY_ADD_BID_RESPONSE, activityParams(MODULE_TYPE_BIDDER, 'bidder4', {}))).to.eql(true); |
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 am not seeing how you're passing in all the extra context required by some rules (adUnit, regs, ortb2, etc), so I was looking for tests about them, and noticed that all the tests requiring it are not calling isActivityAllowed - so I'm guessing that part is still missing?
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.
These describe('evaluateSchema') are unit tests limited only to check if schema functions return correct value for given params function, args, context (where context holds adUnit, bid, etc) so they don't register any activities.
I'm testing if activities are properly registered in describe('evaluateConfig') suite, and since it works correct for example schema:
schema: [{ function: 'adUnitCode', args: ['adUnit-0000'] }]
const bidder1Params = activityParams(MODULE_TYPE_BIDDER, 'bidder1', { adUnit: { code: 'adUnit-0000' } });
and all the schema functions unit tests also work correct, I didn't implement "end-to-end" tests for all possible schemas functions.
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.
Here's where parameters are passed:
adapterManager.ts
auction.ts
test/spec/modules/rules_spec.js
Outdated
|
|
||
| it('should evaluate gppSidIn condition', function() { | ||
| const context1 = { | ||
| regs: { |
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.
why is regs outside of ortb2 for this rule?
|
Tread carefully! This PR adds 1 linter warning (possibly disabled through directives):
|
|
Tread carefully! This PR adds 1 linter warning (possibly disabled through directives):
|
|
@mkomorski can we start the docs pr? |
|
|
|
Hi all @mkomorski @monis0395 Regarding the Math.random That is how PBS does it if I am not mistaken. I get both reasonings, so I feel like maybe we should do both and make it configurable? I have been asked by our data science team before to make decisions as granular as possible, per auction so that is my reasoning for asking. |
|
I am fine with using per auction level too, as long as it is not generated at every request level.
Here, the |
|
Yes sorry if I worded incorrectly I agree, its fine to just get the random number once per auction and use when selecting each rule. |
modules/rules/index.ts
Outdated
| } | ||
|
|
||
| const schemaEvaluators = { | ||
| percent: (args, context) => () => dep.getGlobalRandom() * 100 < args[0], |
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.
is this not always using one math.random per page load?
I was thinking each auction would be able to select a new random? Sorry If I am missing something here?
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'd use a WeakMap with the keys being the auctions from auctionManager.index.getAuction
Yes! Also if it is configurable at the user level or the auction level, that would be great @robertrmartinez @mkomorski |
|
|
||
| const stageRules = config.ruleSets; | ||
|
|
||
| assignModelGroups(stageRules || []); |
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.
so we are picking one model per page load.
I have a similar comment on this being I would think this would want to be random per auction as to get the most uniform spread of model distributions.
PBS being stateless does everything new each auction.
I guess this becomes a bit murky here because we are just hooking into auction via activityControls which is not per auction rather per bidder.
Curious on others thoughts on this.
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.
We could perhaps use the existing requestBidsHook to optionally run assignModelGroups each time?
Though I do not think auctionId is guaranteed to be generated at this point yet so using that to offset model selected may not work.
And if you run auctions back to back things may get weird with analytics if we just run assignModelGroups without some sort of assignment
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 think it's possible to achieve both calculating and assigning model groups on every auction and use activity controls by running the whole current logic in startAuction hook, pass auctionId to activity controls rules params and then unregister the rules on auction end. If this is how it works on pbs, we could just do the same, without making it optional. Also curious on others opinion on that
|
@mkomorski I’m assuming the country value will be set by the publisher through the ortb2 setConfig API so we can run country-based rules. But if a third-party rules provider creates rules that depend on country and the publisher forgets to pass it, how common is that? Would we need to rely on third-party APIs to fill in the country field in ortb2? Also, do you think the browser should be another parameter we can use in rules — for example, including or excluding a bidder based on the user’s browser? Lastly, regarding the bidPrice rule — I assume it removes bids below a certain price. But since the main goal of this module is to exclude bidders before sending them requests. Would love to hear your thoughts. |
@pm-kapil-tuptewar This is a basic version of the module based on what was implemented in the Prebid Server. I think it would be best to release it now and then actively extend it based on what users request in terms of new functionalities. Regarding |
|
thanks @mkomorski for the details. |
| method: string; | ||
| }; | ||
| auctionDelay?: number; | ||
| } |
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.
Hi @mkomorski, similar to the priceFloors and timeoutRtdProvider modules, which accept both static configuration data and endpoint-based data, can we adopt a comparable structure within shapingRules module as well?
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.
+1 to this we should support both
modules/rules/index.ts
Outdated
| const auctionId = context.bid?.auctionId; | ||
| return dep.getGlobalRandom(auctionId) * 100 < args[0] | ||
| }, | ||
| adUnitCode: (args, context) => () => context.adUnit.code === args[0], |
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.
Hi @mkomorski, while testing with the above example, I observed that this condition consistently evaluates to false.
The conditions like context.adUnit.code === args[0] or context.ortb2?.device?.geo?.country === args[0] are consistently evaluating to false because context.adUnit.code and context.ortb2.device.geo.country are strings, whereas args[0] is an object, resulting in a data type mismatch. Please let me know if I may have misunderstood something.
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.
Hi @pm-komal-kumari. Im not sure why you assume args[0] to be an object. In current shape it should be string, however I double checked with the prebid server implementation and in fact functions like adUnitCode should just return the value and comparision value should be took from conditions, so I updated the code. Please check the newest json file
|
another thing is can we provide
regarding other schemaEvaluators, could we add in a hook to add custom schemaValidators? Similar to additionalSchemaFields in the priceFloors module? pbjs.setConfig({
shapingRules: {
// config stuff
extraSchemaEvaluators: {
browser: (args, context) => {
// some fancy code to return browser string
}
}
}
}); |
Yes 👍 |
This module is scoped to define which bidders should be in a given auction based on a defined set of parameters. That would save money for the host company and for the bidder by eliminating network traffic for scenarios where they aren't likely to bid. It addresses these use cases:
This feature is also of interest to the Prebid Sustainability Taskforce, since making fewer requests saves money and reduces carbon emissions.
Type of change
Bugfix
Feature
New bidder adapter
Updated bidder adapter
Code style update (formatting, local variables)
Refactoring (no functional changes, no api changes)
Build related changes
CI related changes
Does this change affect user-facing APIs or examples documented on http://prebid.org?
Other
Description of change
Other information
#12663