-
-
Notifications
You must be signed in to change notification settings - Fork 6
Interaction Tracking -- Observer context switching lifecycle. #10
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
Interaction Tracking -- Observer context switching lifecycle. #10
Conversation
Forgive my poor commit hygiene, lets comment on the Files Changed tab rather than on commits =O |
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.
Left some initial thoughts. Let's chat again after you've had a chance to read them.
By the way, you'll need to fetch and pull the branch you're based on. It's outdated and there are conflicts.
git fetch bvaughn
git rebase bvaughn/interaction-tracking
) => void; | ||
} | ||
|
||
const observers: Array<InteractionContextObserver> = []; |
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 creation of this Array should be done within a __PROFILE__
conditional so it's only included in development and profiling builds (and not production).
|
||
export function registerInteractionContextObserver( | ||
observer: InteractionContextObserver, | ||
): void { |
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.
Similarly, these methods should all be no-ops for production builds, e.g.:
export function registerInteractionContextObserver(
observer: InteractionContextObserver,
): void {
if (!__PROFILE__) {
return;
}
observers.push(observer);
}
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow | ||
*/ |
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 don't think this module should be part of the interaction-tracking package. Seems like it should be part of a separate package that depends on interaction-tracking?
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.
Yes correct, this was included as a proof of concept just to show how we'd use the API. I'll remove it.
startZoneContinuation(interactions); | ||
let contextIDDispenser: number = 0; | ||
|
||
export function startContinuation(context: SettableContext | null): void { |
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 changed from an array of Whoops, disregard this comment. I meant to delete it.Interactions
to a single SettableContext
. That seems wrong to me.
} | ||
} | ||
|
||
export function registerInteractionContextObserver(observer) { |
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.
Both getSettableContext
and registerInteractionContextObserver
could just be exported as-is from InteractionZone
. If you update the version of my branch this PR is based on, that's what I'm doing for all but the track
function (since it adds a small amount of additional behavior).
Or maybe we should just merge the two modules at this point. Especially since this PR has kind of coupled the zone's context type with Interaction
.
@@ -64,6 +107,12 @@ export function startContinuation(context: ZoneContext | null): void { | |||
); | |||
continuationContext = context; | |||
isInContinuation = true; | |||
invariant( |
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.
super tiny nit: Seems like this invariant
belongs at the beginning of the function with the other one.
return ({ | ||
__context: context, | ||
__id: id, | ||
__startCount: 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.
nit: Can't this just be a boolean?
} | ||
|
||
let continuationContext: SettableZoneContext | null = null; | ||
let currentContext: Array<ZoneContext> | null = null; | ||
let isInContinuation: boolean = 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.
isInContinuation
was only necessary when continuationContext
was a nullable param to startContinuation
. If it's non-nullable, we can remove isInContinuation
and just check continuationContext !== null
in our invariants.
const context = isInContinuation ? continuationContext : currentContext; | ||
const id = ++executionID; | ||
__onWrappedContextScheduled(context, id); | ||
return ({ |
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 SettableZoneContext.__context
type Array<ZoneContext>
doesn't seem to line up with the fact that ZoneContext
might be null. I think this function needs to check if context
is null and just return null too if it is? I'm surprised Flow didn't catch this, unless I'm reading it wrong.
|
||
InteractionTracking.startContinuation(null); | ||
expect(InteractionTracking.getCurrentEvents()).toEqual(null); | ||
InteractionTracking.stopContinuation(); |
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'd you remove these tests? I think they're still useful.
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 can't pass null to startContinuation anymore. We'll need some sort of unwrap method to accomplish what is attempted 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.
Hm. I think there's still a disconnect in nullability as my other comment mentioned. I'll check it out when I'm merging/rebasing.
@@ -42,19 +62,42 @@ export function wrap(callback: Function): Function { | |||
} | |||
|
|||
const wrappedContext = currentContext; | |||
const id = ++executionID; |
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 value in differentiating the execution id and the context/interaction id(s)? It's fine, I'm just curious what it lets us do.
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 execution ID allows us to pair up calls of onContextScheduled/Starting/Ended. Check out how InteractionProfiler is using the ID.
The introduction of I think the solution is to disallow |
if (!__PROFILE__) { | ||
return null; | ||
} | ||
const context = isInContinuation ? continuationContext : currentContext; |
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.
Something about this seems wrong, but I might be getting your PR– and my updated branch– mixed up...but if getSettableContext()
is called while in a continuation– and this function returns continuationContext
– won't that cause an error the next time it's called?
I'll try to tackle this when merging things, but we may need to revisit this question.
Okay. I merged my branch into this branch and addressed my own PR feedback. I am pretty satisfied with where we arrived. |
I'm going to move forward with this so I can start updating the integration PR (facebook#13253) but let's circle back and talk on Monday to address any concerns or feedback you have. |
Gah, actually– we'll still need to revisit continuations. Since multiple interactions might get batched into a single React commit, React will need the ability to continue multiple interactions at once. I think this could be made to mostly work, but is a little tricky when it comes to the concept of an "execution id". Multiple IDs would potentially be "scheduled" individually and then subsequently continued in a batch. I guess the API could just accept an array of continuations to start/stop? It's also a bit tricky, since React unwinds stacks of interactions in order to store them as a flat list of unique interactions. 🤔 |
I also think it would probably be better if the API supported requesting a continuation for a specific interaction because– as it currently stands, React might end up requesting a lot of unnecessary continuations. |
I thought about this a lot on my afternoon run and I think I have some ideas that will work. Stay tuned! |
* Fixes docker-compose & pg initialization - ./scripts/init_db.sh is not executable (/bin/bash: bad interpreter: Permission denied) - same script fails because user is already created, only table creation is necessary. * Actually fix docker-compose development workflow * Incorporate PR feedback * Remove credentials.json
This PR builds on PR facebook#13234 which Introduces an experimental Interaction Tracking API.
The goal of this PR is to add a lifecycle around the context switching that happens inside of Interaction Tracking so that we can implement a profiler that can reconstruct the DAG of execution (InteractionProfiler.js)
The changes in this PR are:
onContextScheduled
,onContextStarting
,onContextEnded
.getSettableContext
method to be used in conjunction withstartContinuation
.getSettableContext
calls theonContextScheduled
lifecycle which will trigger our Observer to increment the reference count for the current interaction contexts.