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: Refactor variation method and consistency tracking. #264

Merged
merged 8 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LDConsistencyCheck, LDMigrationStage } from '../src';
import { LDMigrationStage } from '../src';
import { LDMigrationOrigin } from '../src/api/LDMigration';
import MigrationOpTracker from '../src/MigrationOpTracker';

Expand Down Expand Up @@ -160,7 +160,7 @@ it('includes if the result was consistent', () => {
},
);
tracker.op('read');
tracker.consistency(LDConsistencyCheck.Consistent);
tracker.consistency(() => true);
tracker.invoked('old');
tracker.invoked('new');

Expand All @@ -185,7 +185,7 @@ it('includes if the result was inconsistent', () => {
tracker.op('read');
tracker.invoked('old');
tracker.invoked('new');
tracker.consistency(LDConsistencyCheck.Inconsistent);
tracker.consistency(() => false);

const event = tracker.createEvent();
expect(event?.measurements).toContainEqual({
Expand Down
8 changes: 2 additions & 6 deletions packages/shared/sdk-server/src/LDClientImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import {
LDClient,
LDFlagsState,
LDFlagsStateOptions,
LDMigrationDetail,
LDMigrationOpEvent,
LDMigrationStage,
LDMigrationVariation,
LDOptions,
LDStreamProcessor,
} from './api';
Expand Down Expand Up @@ -307,7 +307,7 @@ export default class LDClientImpl implements LDClient {
key: string,
context: LDContext,
defaultValue: LDMigrationStage,
): Promise<LDMigrationDetail> {
Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed this as it isn't "detail" any longer.

): Promise<LDMigrationVariation> {
const convertedContext = Context.fromLDContext(context);
const [{ detail }, flag] = await this.evaluateIfPossible(
key,
Expand All @@ -328,8 +328,6 @@ export default class LDClientImpl implements LDClient {
};
return {
value: defaultValue,
reason,
checkRatio,
tracker: new MigrationOpTracker(
key,
contextKeys,
Expand All @@ -343,9 +341,7 @@ export default class LDClientImpl implements LDClient {
};
}
return {
...detail,
value: detail.value as LDMigrationStage,
checkRatio,
tracker: new MigrationOpTracker(
key,
contextKeys,
Expand Down
16 changes: 7 additions & 9 deletions packages/shared/sdk-server/src/Migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ export function LDMigrationError(error: Error): { success: false; error: Error }
interface MigrationContext<TPayload> {
payload?: TPayload;
tracker: LDMigrationTracker;
checkRatio?: number;
}

/**
Expand Down Expand Up @@ -239,7 +238,6 @@ export default class Migration<
const res = await this.readTable[stage.value]({
payload,
tracker: stage.tracker,
checkRatio: stage.checkRatio,
});
stage.tracker.op('read');
this.sendEvent(stage.tracker);
Expand Down Expand Up @@ -274,13 +272,13 @@ export default class Migration<
oldValue: LDMethodResult<TMigrationRead>,
newValue: LDMethodResult<TMigrationRead>,
) {
if (this.config.check && shouldSample(context.checkRatio ?? 1)) {
if (oldValue.success && newValue.success) {
const res = this.config.check(oldValue.result, newValue.result);
context.tracker.consistency(
res ? LDConsistencyCheck.Consistent : LDConsistencyCheck.Inconsistent,
);
}
if (!this.config.check) {
return;
}

if (oldValue.success && newValue.success) {
// Check is validated before this point, so it is force unwrapped.
context.tracker.consistency(() => this.config.check!(oldValue.result, newValue.result));
}
}

Expand Down
9 changes: 6 additions & 3 deletions packages/shared/sdk-server/src/MigrationOpTracker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LDEvaluationReason, LDLogger } from '@launchdarkly/js-sdk-common';
import { internal, LDEvaluationReason, LDLogger } from '@launchdarkly/js-sdk-common';

import { LDMigrationStage, LDMigrationTracker } from './api';
import {
Expand Down Expand Up @@ -55,8 +55,11 @@ export default class MigrationOpTracker implements LDMigrationTracker {
this.errors[origin] = true;
}

consistency(result: LDConsistencyCheck) {
this.consistencyCheck = result;
consistency(check: () => boolean) {
if (internal.shouldSample(this.checkRatio ?? 1)) {
const res = check();
this.consistencyCheck = res ? LDConsistencyCheck.Consistent : LDConsistencyCheck.Inconsistent;
}
}

latency(origin: LDMigrationOrigin, value: number) {
Expand Down
6 changes: 3 additions & 3 deletions packages/shared/sdk-server/src/api/LDClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LDContext, LDEvaluationDetail, LDFlagValue } from '@launchdarkly/js-sdk-common';

import { LDMigrationDetail, LDMigrationOpEvent } from './data';
import { LDMigrationOpEvent, LDMigrationVariation } from './data';
import { LDFlagsState } from './data/LDFlagsState';
import { LDFlagsStateOptions } from './data/LDFlagsStateOptions';
import { LDMigrationStage } from './data/LDMigrationStage';
Expand Down Expand Up @@ -135,13 +135,13 @@ export interface LDClient {
* @param defaultValue The default value of the flag, to be used if the value is not available
* from LaunchDarkly.
* @returns
* A Promise which will be resolved with the result (as an{@link LDMigrationDetail}).
* A Promise which will be resolved with the result (as an{@link LDMigrationVariation}).
*/
variationMigration(
key: string,
context: LDContext,
defaultValue: LDMigrationStage,
): Promise<LDMigrationDetail>;
): Promise<LDMigrationVariation>;

/**
* Builds an object that encapsulates the state of all feature flags for a given context.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,21 @@ export interface LDMigrationTracker {
error(origin: LDMigrationOrigin): void;

/**
* Report the result of a consistency check.
* Check the consistency of a read result. This method should be invoked if the `check` function
* is defined for the migration and both reads ("new"/"old") were done.
*
* @param result The result of the check.
* The function will use the checkRatio to determine if the check should be executed, and it
* will record the result.
*
* Example calling the check function from the migration config.
* ```
* context.tracker.consistency(() => config.check!(oldValue.result, newValue.result));
* ```
*
* @param check The function which executes the check. This is not the `check` function from the
* migration options, but instead should be a parameter-less function that calls that function.
*/
consistency(result: LDConsistencyCheck): void;
consistency(check: () => boolean): void;

/**
* Call this to report that an origin was invoked (executed). There are some situations where the
Expand Down Expand Up @@ -64,40 +74,17 @@ export interface LDMigrationTracker {
}

/**
* Detailed information about a migration variation.
* Migration value and tracker.
*/
export interface LDMigrationDetail {
export interface LDMigrationVariation {
/**
* The result of the flag evaluation. This will be either one of the flag's variations or
* the default value that was passed to `LDClient.variationDetail`.
*/
value: LDMigrationStage;

/**
* The index of the returned value within the flag's list of variations, e.g. 0 for the
* first variation-- or `null` if the default value was returned.
*/
variationIndex?: number | null;

/**
* An object describing the main factor that influenced the flag evaluation value.
*/
reason: LDEvaluationReason;

/**
* A tracker which which can be used to generate analytics for the migration.
*/
tracker: LDMigrationTracker;

/**
* When present represents a 1 in X ratio indicating the probability that a given operation
* should have its consistency checked. A 1 indicates that it should always be sampled and
* 0 indicates that it never should be sampled.
*/
checkRatio?: number;

/**
* Sampling ratio for the migration event. Defaults to 1 if not specified.
*/
samplingRatio?: number;
}
2 changes: 1 addition & 1 deletion packages/shared/sdk-server/src/api/data/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './LDFlagsStateOptions';
export * from './LDFlagsState';
export * from './LDMigrationStage';
export * from './LDMigrationDetail';
export * from './LDMigrationOpEvent';
export * from './LDMigrationVariation';