CORE-51982 Use sendBeacon for link tracking.#598
Conversation
| <h2>Large Payloads</h2> | ||
| <p>This page tests send really large payloads to the edge.</p> | ||
| <p> | ||
| All those requests should not use beacon calls, and should not fail. |
There was a problem hiding this comment.
This wasn't accurate. The command options include documentUnloading: true, which means Alloy does use sendBeacon. Depending on the browser, some payload will fail to be sent using sendBeacon and Alloy will fall back to fetch.
There was a problem hiding this comment.
Wouldn't this be configured without documentUnloading to avoid sendBeacon limit then?
There was a problem hiding this comment.
I'm not sure I understand your question, but this page is to test what happens when sendBeacon is used, so I believe the configuration (documentUnloading: true) is correct, but this description we had previously didn't make sense and didn't correlate with our configuration.
| addEvent(event) { | ||
| content.events = content.events || []; | ||
| content.events.push(event.toJSON()); | ||
| content.events.push(event); |
There was a problem hiding this comment.
This change here probably deserves some explanation. I believe we were calling event.toJSON() here because when we log the payload to the console, we don't want the event's methods and stuff showing up on the logged object. Since the time this was written, we've adjusted how we log the payload to the console to be smarter: https://github.com/adobe/alloy/blob/master/src/core/network/injectSendNetworkRequest.js#L24-L39
When we log the payload, we serialize and then deserialize the object. When the object is serialized, JSON.parse recursively goes through the payload object, including its events, calling toJSON. Because of this, there's no reason to do event.toJSON() here anymore. We also don't want to do event.toJSON() here anymore because we need access to its methods in the new getDocumentMayUnload method below.
There was a problem hiding this comment.
This also affects when the lastChanceCallback gets called. The cloning of the object is also important so that if the event is queued, when the event is sent, it contains the data as it was when sendEvent was called. We should probably break out some of the toJSON code into a "freeze" method.
There was a problem hiding this comment.
Thanks for pointing this out. I thought I might be missing something. So, with the changes in this PR, the last chance callback would get called when the payload gets serialized, which seems to me to be more appropriate than the way it was previously, since the callback will now be called be as late as possible.
Regarding cloning of customer data, I feel like it should be the responsibility of the data collector to clone the data ASAP, even before it makes its way into the event.
Thoughts on that?
There was a problem hiding this comment.
Pros of the approach in this PR:
- using the lastChanceCallback to set the consent and preferences on pre-consent events is possible
- Customers have the flexibility of giving an object to sendEvent that can change up until the event is serialized or providing a copy
Cons:
- Customers may be confused about when the xdm and data objects are frozen. (We can solve this with documentation)
I'm sold on the change in this PR.
| return networkStrategy({ | ||
| url, | ||
| body: stringifiedPayload, | ||
| documentMayUnload: payload.getDocumentMayUnload() |
There was a problem hiding this comment.
This is the crux of why sendBeacon wasn't being used before. We weren't passing documentMayUnload.
| } else { | ||
| pageUrl = alloyPages[env]; | ||
| } | ||
| // eslint-disable-next-line no-console |
There was a problem hiding this comment.
I was seeing lint warnings.
| payload.addIdentity("IDNS", { | ||
| id: "ABC123" | ||
| }); | ||
| expect(payload.toJSON()).toEqual({ |
There was a problem hiding this comment.
This technically wasn't really serializing. JSON.stringify recursively calls toJSON on the content passed to it, which is a better representation of what we're trying to test.
| addEvent(event) { | ||
| content.events = content.events || []; | ||
| content.events.push(event.toJSON()); | ||
| content.events.push(event); |
There was a problem hiding this comment.
This also affects when the lastChanceCallback gets called. The cloning of the object is also important so that if the event is queued, when the event is sent, it contains the data as it was when sendEvent was called. We should probably break out some of the toJSON code into a "freeze" method.
| } | ||
| if (content.data || !isEmptyObject(data)) { | ||
| content.data = data; | ||
| if (lastChanceCallback) { |
There was a problem hiding this comment.
This modification was to limit the amount we're cloning xdm and data.
| if (xdm) { | ||
| // Clone xdm in case the customer modifies the object | ||
| // between now and the time it gets sent to the server. | ||
| event.setUserXdm(clone(xdm)); |
There was a problem hiding this comment.
Like the comment says, DataCollector is now cloning xdm and data as soon as possible so that if the customer modifies the object between now and the time it gets sent to the server, we use the original state and not the state after modification. What's interesting is that the command option validator we're using (which leverages Yup) also clones this data in some fashion, making this particular clone call unnecessary to accomplish our goal, but yet I prefer that we explicitly clone here anyway so that our intentions are explicit and we're not relying on the validator to do the cloning.
|
|
||
| useEffect(() => { | ||
| eventMergeIdPromise.current.then(eventMergeId => { | ||
| eventMergeIdPromise.current.then(result => { |
There was a problem hiding this comment.
This is a separate fix for something else?
There was a problem hiding this comment.
Yeah, I thought I left a comment somewhere but I don't know where it is now. The event merge ID view in the sandbox was failing because the promise is resolved with an object containing the event merge ID rather than the event merge ID itself.
Bumps [ajv](https://github.com/ajv-validator/ajv) from 8.17.1 to 8.18.0. - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](ajv-validator/ajv@v8.17.1...v8.18.0) --- updated-dependencies: - dependency-name: ajv dependency-version: 8.18.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Description
We weren't using
sendBeaconfor click tracking and now we are.Related Issue
https://jira.corp.adobe.com/browse/CORE-51982
Motivation and Context
We want to be using sendBeacon on link clicks because there's a high likelihood the user is navigating away from the page and we want to ensure the beacon reaches the server.
Screenshots (if appropriate):
Types of changes
Checklist: