Skip to content
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

feat: Use callbacks for evaluation hotpath. #234

Merged
merged 24 commits into from
Aug 21, 2023

Conversation

kinyoklion
Copy link
Member

@kinyoklion kinyoklion commented Aug 11, 2023

This PR changes the evaluation to use callbacks instead of async. In the case where there is no IO there are many cases where execution will just by recursive without being deferred in the task system.

Recursion does have its limits for collections though, large collections do use an immediately resolved promise to prevent the iteration from causing a stack overflow.

Generally speaking the callback depth here should be similar to that in the previous implementation, so it should not cause problems. Though I prefer greatly the async approach in regards to this.

@@ -101,13 +110,52 @@ export default class Evaluator {
}

async evaluate(flag: Flag, context: Context, eventFactory?: EventFactory): Promise<EvalResult> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test compatibility I kept an async version.

@kinyoklion kinyoklion marked this pull request as ready for review August 11, 2023 17:05
Copy link
Contributor

@yusinto yusinto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using callbacks increases complexity make this more difficult to maintain. I feel nervous we are going back to callbacks, simultaneously understand the need for performance. I would like to request in the future we further investigate improving performance with async/await so we can have a win-win.

Are you able to tag this commit "revert to callbacks" so it's easily detectable for future reference please? Thank you.

@kinyoklion
Copy link
Member Author

Using callbacks increases complexity make this more difficult to maintain. I feel nervous we are going back to callbacks, simultaneously understand the need for performance. I would like to request in the future we further investigate improving performance with async/await so we can have a win-win.

Are you able to tag this commit "revert to callbacks" so it's easily detectable for future reference please? Thank you.

Well, we never used callbacks in this implementation. So it isn't really reverting, and it isn't 100% equivalent to the callback implementation from the old implementation.

I can put callbacks in the title though.

@kinyoklion kinyoklion changed the title feat: Do not use async for evaluation hotpath. feat: Use callbacks for evaluation hotpath. Aug 11, 2023
@kinyoklion kinyoklion force-pushed the rlamb/performance-experimentation branch from e9175ee to 8a15e15 Compare August 14, 2023 20:38
@@ -268,7 +269,7 @@ export default class LDClientImpl implements LDClient {
});
}

async allFlagsState(
allFlagsState(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we have to make a manual promise anyway removing the async here may save a small amount of overhead.

`Error for feature flag "${flag.key}" while evaluating all flags: ${res.message}`,
),
);
const doEval = (valid: boolean) =>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some refactoring here to allow the callback version of the initialized function for the sore.

const clientOnly = !!options?.clientSideOnly;
const detailsOnlyIfTracked = !!options?.detailsOnlyForTrackedFlags;

allAsync(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main change. Evaluate the flags concurrently using promises.

This isn't strictly a win for performance, but it does do a couple things.

1.) It should be a consistent win for performance when using persistent stores.
2.) It lowers the risks of stack overflows with the new callback implementation.
3.) It changes the execution behavior to be more like the old SDK. This isn't necessarily positive or negative, but it does have that effect.

@kinyoklion kinyoklion merged commit 27e5454 into main Aug 21, 2023
13 checks passed
@kinyoklion kinyoklion deleted the rlamb/performance-experimentation branch August 21, 2023 19:57
@github-actions github-actions bot mentioned this pull request Aug 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants