Hey team! By any chance is there a changelog for t...
# give-feedback
f
Hey team! By any chance is there a changelog for the javascript SDK across release versions? ๐Ÿ™ We've been using growthbook 0.18.0 on a graphql instance and we recently noticed non-deterministic experiment results (based on user id), wondering if I could see a list of fixes that happened between 0.18.0 and the most up to date 0.21.2
f
Hi Marco. Do you mean your bucketing changed with the change in the SDK versions?
f
@fresh-football-47124 A few of our users reported having intermittency of the availability of one of our features. We tracked their network logs and for the same user; within seconds, a flag resolved false, and then on another request it resolved with a true value
Our experiment has a 100% rollout with 50/50 splits
f
are you evaluating the features client side?
it sounds like a race condition with evaluation of a feature before the setting of attributes
f
On a graphql server we dedicate for front-end, we have a request interceptor that does this per request:
Copy code
use(req: Request, res: Response, next: NextFunction): void {
    const id = getUserIdFromRequest(req);

    const currentGrowthBookUserId = this.growthbook.getAttributes().id;

    if (id && currentGrowthBookUserId !== id) {
      this.growthbook.setAttributes({
        id,
      });
    }

    next();
  }
Ohhh, can
setAttributes
do async tasks in the background that could cause race conditions?
f
one thing to note, setAttributes overwrites the attributes - if ID is the only thing youโ€™re defining, this is fine, but it will erase other attributes
๐Ÿ‘ 1
f
Yeah in this graphql instance we're only doing ID atm ๐Ÿ™
f
@future-teacher-7046 do you whats happening?
f
Are you sharing a single GrowthBook instance between multiple back end requests? We recommend instead to have a separate instance for every request.
f
Yes, we have a singleton instance being shared across requests, we just update the attributes on each one
@future-teacher-7046 in this scenario should these instances be created on each and every request or do you recommend persisting these instances per user in memory? ๐Ÿ˜ฎ
f
We recommend creating a brand new instance for every request. Creating an instance is fast and cheap, the only expensive part is fetching the list of features from the API. If you're using the new built-in fetching (by specifying
apiHost
and
clientKey
), it has caching by default. If you're implementing your own fetching, make sure to do that outside of the request and re-use the same JSON object for each SDK instance. For express, it would look something like this:
Copy code
app.use(function(req, res, next) {
  // Create a GrowthBook Context
  req.growthbook = new GrowthBook({
    apiHost: "<https://cdn.growthbook.io>",
    clientKey: "sdk-abc123",
    attributes: {
      // TODO: real targeting attributes from the request
      id: req.cookies.ID
    },
    trackingCallback: (experiment, result) => {
      // TODO: Use your real analytics tracking system
      console.log("Viewed Experiment", {
        experimentId: experiment.key,
        variationId: result.variationId
      });
    }
  });

  // Clean up at the end of the request
  res.on('close', () => req.growthbook.destroy());

  // Wait for features to load (will be cached in-memory for future requests)
  req.growthbook.loadFeatures()
    .then(() => next())
    .catch((e) => {
      console.error("Failed to load features from GrowthBook", e);
      next();
    })
})
f
Awesome! The issue is easily reproducible in our end, will re-test after making these changes ๐Ÿ™ thank you!