-
Notifications
You must be signed in to change notification settings - Fork 732
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
Generate Unique Bidrequest IDs for Amp Auctions #1938
Generate Unique Bidrequest IDs for Amp Auctions #1938
Conversation
givenInTagId string | ||
givenInStoredRequest json.RawMessage | ||
givenGenerateStoredRequestId bool | ||
expected int |
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.
Might want to call this expectedIDLength
as at first I was wondering how you arranged it to have generated ID always be "36".
endpoints/openrtb2/auction.go
Outdated
@@ -1448,7 +1449,13 @@ func getStoredRequestId(data []byte) (string, bool, error) { | |||
return "", true, errors.New("ext.prebid.storedrequest.id must be a string") | |||
} | |||
|
|||
return string(value), true, nil | |||
// Generates Request ID if flag is set to true -- used to solve issue with amp auctions |
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 is supposed to return the ID of the stored request, not the openrtb request's ID. Also by generating a random stored request ID you are virtually guaranteeing that the stored request lookup will fail, and potentially hammering the database with failing lookups.
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.
To avoid having to unmarshal/remarshal the stored request json, you probably want to patch the retrieved stored request with { "id": "<generated uuid>" }
before applying the patch to the incoming request. Unless we want the spec that the flag should always overwrite any incoming request IDs, in which case we will have to do something else. But I don't see a use case for overwriting the request ID in the incoming request other than the case where a PBS instance is only supporting a client that always sends a non-random ID, and no other clients. But in this case it really should be fixed on the client side rather than hacking PBS to enforce unique IDs in all cases.
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.
Just to keep this PR updated, Hans and I talked about these comments and what I need to do to properly address them! A commit will be pushed today or tomorrow with the proper fixes / tests.
791257e
to
895764a
Compare
endpoints/openrtb2/auction.go
Outdated
requestErrorJson, errL := storedRequestErrorChecker(err, requestJson, storedRequests, storedBidRequestId) | ||
return requestErrorJson, nil, errL | ||
} | ||
} else if !deps.cfg.GenerateRequestId && hasStoredBidRequest { |
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.
If you reach this line, and hasStoredBidRequest
is true, then you know !deps.cfg.GenerateRequestId
also has to be true, you don't need to test both.
Another potential logic flow is:
} else if !deps.cfg.GenerateRequestId && hasStoredBidRequest { | |
storedReqForPatch = '' | |
if hasStoredBidRequest { | |
storedReqForPatch = storedRequests[storedBidRequestId] | |
} | |
if deps.cfg.GenerateRequestId { | |
uuidPatch, err := generateUuidForBidRequest() | |
if hasStoredBidRequest { | |
storedReqForPatch, err := jsonpatch.MergePatch(storedRequests[storedBidRequestId], uuidPatch) | |
} else { | |
storedReqForPatch := uuidPatch | |
hasStoredBidRequest = true | |
} | |
} | |
if hasStoredBidRequest { | |
resolvedRequest, err = jsonpatch.MergePatch(requestJson, storedReqForPatch) | |
} |
with the error handling and other supporting code included.
endpoints/openrtb2/auction_test.go
Outdated
@@ -1089,7 +1161,7 @@ func TestOversizedRequest(t *testing.T) { | |||
&mockStoredReqFetcher{}, | |||
empty_fetcher.EmptyFetcher{}, | |||
empty_fetcher.EmptyFetcher{}, | |||
&config.Configuration{MaxRequestSize: int64(len(reqBody) - 1)}, | |||
&config.Configuration{MaxRequestSize: int64(len(reqBody) - 1), GenerateRequestId: false}, |
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.
The nil value of a boolean is false
, so you shouldn't have to explicitly set these values.
2747163
to
a37cbec
Compare
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.
LGTM
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 is missing the {{UUID}} macro, but otherwise looks solid. I'm good if you'd like to add the macro in a follow-up PR. The Java version only performs this behavior for app requests, is that a necessary restriction?
endpoints/openrtb2/auction.go
Outdated
@@ -1567,3 +1585,35 @@ func getAccountID(pub *openrtb2.Publisher) string { | |||
} | |||
return metrics.PublisherUnknown | |||
} | |||
|
|||
func storedRequestErrorChecker(err error, requestJson []byte, storedRequests map[string]json.RawMessage, storedBidRequestId string) []error { |
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.
The err
argument is not used. Please consider removing it.
endpoints/openrtb2/auction_test.go
Outdated
newRequest, _, errList := deps.processStoredRequests(context.Background(), json.RawMessage(test.givenRawData)) | ||
for _, err := range errList { | ||
assert.Empty(t, err, test.description) | ||
} |
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.
You don't need to use a loop here. You can simply write:
newRequest, _, errList := deps.processStoredRequests(context.Background(), json.RawMessage(test.givenRawData))
assert.Empty(t, errList, test.description)
endpoints/openrtb2/amp_auction.go
Outdated
@@ -344,6 +347,15 @@ func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req | |||
errs = []error{err} | |||
return | |||
} | |||
// Generates Request ID if flag is set to 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.
Nitpick: Comment does not seem valuable.
endpoints/openrtb2/auction.go
Outdated
isAppRequest, err := checkIfAppRequest(requestJson) | ||
if err != nil { | ||
return nil, nil, []error{err} | ||
} |
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.
Looks good. I like that you've extracted the check to a method. To increase performance, I recommend moving this check within the deps.cfg.GenerateRequestID
check, such that we only bother to check for an app request if the feature is turned on. I usually don't recommend nesting, but in this case it's a performance improvement in certain cases.
d860aa1
to
c6d38aa
Compare
c6d38aa
to
86204e0
Compare
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.
LGTM
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.
The AMP flow checks out with local end to end tests. Please see me comment for a bug in the APP flow.
return nil, nil, []error{err} | ||
} | ||
if isAppRequest { | ||
uuidPatch, err := generateUuidForBidRequest(deps.uuidGenerator) |
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.
The uuidPatch
is being generated for all app requests, but it should only be generated when also hasStoredBidRequest
is 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.
Why do we want to disable generating request IDs when there is no stored request for an App request? Is that a performance tweak that we expect we should only need a request ID if there was a stored request involved?
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.
Talked to SyntaxNode and this is desired behavior. Should be documented somewhere, in the end (not in the code, but the docs elsewhere) since it is not intuitively obvious when this feature should or should not kick in.
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.
LGTM
Addressing this issue here #1507
I've added a configuration boolean flag,
GenerateRequestId
, which when set to true, will generate a uuid for auction bid requests, which can be used to solve the amp auction issue found here #1507This generation can occur in two different functions:
GenerateRequestId
is true, and if so, we generate a uuid and patch it into the request