launchdarkly / node-server-sdk

LaunchDarkly Server-side SDK for Node
Other
79 stars 65 forks source link

Manual variation tracking #188

Closed flovilmart closed 1 year ago

flovilmart commented 4 years ago

Is your feature request related to a problem? Please describe.

We're using the Launch Darkly SDK in cloudfront lambda to assign experiments that trigger server side rendering through the allFlags(). The problem is that the variations are not reported to LD. We don't use the LD SDK in the client side.

In the node server when consuming an experiment, we check that an override is not present in the query string or a header. However, we are not able to track the experiment consumption in the launch darkly dashboard.

Describe the solution you'd like

We'd like to be able to manually track the evaluation on the server; exposing this feature: https://github.com/launchdarkly/node-server-sdk/blob/master/index.js#L278

eli-darkly commented 4 years ago

This description is slightly unclear to me. I can't tell if you are asking for 1. the ability to send an arbitrary analytics event without having done an evaluation, or 2. a change in the behavior of allFlags() so that it always sends analytics events for all of the flags.

If it is 1, I can't see why this would be necessary, since if you want to generate an event for a flag you can simply call variation().

Could you please say in more detail exactly what you want to be able to do in your code and what its effect should be, and also why this cannot be done with the existing API?

flovilmart commented 4 years ago

exactly what you want to be able to do in your code and what its effect should be, and also why this cannot be done with the existing API?

I want to send an event to launch darkly that a flag has be arbitrarily evaluated.

Why?

Because we always evaluate the flags through allFlags(). Therefore we never know when a flag is evaluated. Also, we do not pass / know the id of the user used to generate the flag as the flag is consumed in a different realm if you wish. We pass around the state of the flags though headers, allowing effective caching as the number of possible values for the flags is finite and small. It is designed to leverage cache in cloudfront while triggering invalidation IFF the variant of the page is not present. Sometimes, this variant triggers server re-renders, which trigger API calls to sub services. We use variant values instead of user ID so we have predictive behaviours and are able to force different code paths to be executed.

a change in the behavior of allFlags() so that it always sends analytics events for all of the flags.

This isn't ideal as this won't reflect at all how many times a flag is effectively consumed.

If it is 1, I can't see why this would be necessary, since if you want to generate an event for a flag you can simply call variation().

This isn't that simple, we don't necessarily have the user ID at the place we consume the flag and we want to track it's consumption, therefore there could be a mismatch between what one part of the app knows and the other one knows.

eli-darkly commented 4 years ago

This isn't that simple, we don't necessarily have the user ID at the place we consume the flag and we want to track it's consumption, therefore there could be a mismatch between what one part of the app knows and the other one knows.

But an evaluation event requires a user. That is part of the analytics data: the flag was evaluated for this particular user. So if you are in some part of the code where you want to use the already-computed flag value, and you also want to generate an event at that point, any mechanism that could be used to generate that event is still going to need some user properties.

If you don't care at all about any properties of the analytics other than simply the number of times the flag was evaluated, then you could simply call variation() with a dummy user and ignore the result value. However, then the event would not reflect the real flag value that you got for the real user, so the analytics data would only be correct in terms of the total number of evaluations, not how many evaluations got value A versus value B.

flovilmart commented 4 years ago

However, then the event would not reflect the real flag value that you got for the real user, so the analytics data would only be correct in terms of the total number of evaluations, not how many evaluations got value A versus value B.

and this is the problem that I face. I know the particular value at that point, I merely need to 'report' it to Launch Darkly.

This is the workaround that we have:

export function init(sdkKey: string, additionalOptions?: any): LDClient {
  const ldClient = LaunchDarkly.init(sdkKey, additionalOptions);
  const ldConfig = configuration.validate(additionalOptions);
  const diagnosticId = diagnostics.DiagnosticId(sdkKey);
  const diagnosticsManager = diagnostics.DiagnosticsManager(
    ldConfig,
    diagnosticId,
    new Date().getTime(),
  );
  const eventFactory = EventFactory(false);
  const eventProcessor = EventProcessor(
    sdkKey,
    ldConfig,
    undefined,
    diagnosticsManager,
  );
  ldClient.trackVariation = function (flag, user, value) {
    eventProcessor.sendEvent(
      eventFactory.newEvalEvent({ key: flag, trackEvents: true }, user, {
        value,
      }),
    );
  };
  return ldClient;
}