-
Notifications
You must be signed in to change notification settings - Fork 5
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: Auto-assignment tracking #22
Conversation
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.
will review again once other changes are in
packages/node/src/types/variant.ts
Outdated
@@ -23,8 +23,8 @@ export type Variants = { | |||
|
|||
export type FlagResult = { | |||
value: string; | |||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |||
payload: any | null | undefined; | |||
payload: string; |
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 has payload been converted to a string 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.
Awesome work Tim! Lets meet on Monday to go over these review comments.
let sb = | ||
this.user.user_id?.trim() + ' ' + this.user.device_id?.trim() + ' '; |
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: You can use a template string to start with, and you should use a different variable name, sb
is used in java due to the StringBuilder
class which is not used in javascript. I would prefer:
let sb = | |
this.user.user_id?.trim() + ' ' + this.user.device_id?.trim() + ' '; | |
let canonical = `${this.user.user_id?.trim()} ${this.user.device_id?.trim()} `; |
this.user.user_id?.trim() + ' ' + this.user.device_id?.trim() + ' '; | ||
for (const key of Object.keys(this.results).sort()) { | ||
const value = this.results[key]; | ||
sb += key.trim() + ' ' + value?.value?.trim() + ' '; |
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.
Use template string here.
export interface AssignmentService { | ||
track(assignment: Assignment): Promise<void>; | ||
} | ||
|
||
export interface AssignmentFilter { | ||
shouldTrack(assignment: Assignment): boolean; | ||
} |
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.
Absolute super minor nit: I prefer interface definitions at the top of the file :)
import { DAY_MILLIS } from 'src/assignment/assignment-service'; | ||
import { Cache } from 'src/util/cache'; | ||
|
||
export const DEFAULT_FILTER_CAPACITY = 65536; |
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 know you're just transcribing my code, so this is really my fault, but: Remove this default from this file, set the default in a DefaultAssignmentConfiguration
object in the config.ts
file. Then object spread the input with the defaults (as we do with the base configuration) in local evaluation client constructor.
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.
import { sleep } from 'src/util/time'; | ||
import { MockAssignmentFilter } from 'test/local/util/mockAssignmentFilter'; | ||
|
||
test('filter - single assignment', async () => { |
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'm skimming the tests, just note:
Please add more tests if you don't understand some part of the code and want to make sure it's doing what you expect
You will have to fix all the bugs that eventually make it into production :)
import { Assignment, AssignmentFilter } from 'src/assignment/assignment'; | ||
import { Cache } from 'src/util/cache'; | ||
|
||
export class MockAssignmentFilter implements AssignmentFilter { |
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.
Can you explain why we need an explicit mock class not just using jest?
}); | ||
await client.start(); | ||
await client.evaluate({ user_id: 'tim.yiu@amplitude.com' }); | ||
await sleep(4000); |
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.
Whats the purpose of these 4000 sleeps?
const client = new LocalEvaluationClient(apiKey, {}); | ||
await client.start(); | ||
await client.evaluate({ user_id: 'tim.yiu@amplitude.com' }); | ||
await sleep(4000); |
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.
Whats the purpose of these 4000 sleeps?
…Service construction and AssignmentConfiguration in local client.ts
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 awesome 🥇
Couple of comments, please implement assignment filtering and export the new config before merging.
packages/node/src/types/config.ts
Outdated
}; | ||
|
||
export type AssignmentConfiguration = { |
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 need to export this & NodeOptions
in the index.ts file.
packages/node/src/local/client.ts
Outdated
@@ -85,6 +113,7 @@ export class LocalEvaluationClient { | |||
this.flags, | |||
); | |||
const results: Results = evaluation.evaluate(this.flags, user); | |||
void this.assignmentService?.track(new Assignment(user, results)); |
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.
filter results before passing to track.
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.
Oh, last thing, we always want to include flags with type mutual-exclusion-group
or holdout-group
in the assignment.
This is a bit of a hack until we add topological sorting before evaluation in this SDK also :)
Summary
Added auto-assignment tracking feature
Checklist