https://www.growthbook.io/ logo
f

fresh-keyboard-9333

02/15/2023, 9:50 PM
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

fresh-football-47124

02/16/2023, 3:25 AM
Hi Marco. Do you mean your bucketing changed with the change in the SDK versions?
f

fresh-keyboard-9333

02/16/2023, 4:23 PM
@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

fresh-football-47124

02/16/2023, 4:24 PM
are you evaluating the features client side?
it sounds like a race condition with evaluation of a feature before the setting of attributes
f

fresh-keyboard-9333

02/16/2023, 4:25 PM
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

fresh-football-47124

02/16/2023, 4:26 PM
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

fresh-keyboard-9333

02/16/2023, 4:26 PM
Yeah in this graphql instance we're only doing ID atm ๐Ÿ™
f

fresh-football-47124

02/17/2023, 4:59 AM
@future-teacher-7046 do you whats happening?
f

future-teacher-7046

02/17/2023, 10:41 AM
Are you sharing a single GrowthBook instance between multiple back end requests? We recommend instead to have a separate instance for every request.
f

fresh-keyboard-9333

02/17/2023, 4:15 PM
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

future-teacher-7046

02/17/2023, 4:21 PM
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

fresh-keyboard-9333

02/17/2023, 5:21 PM
Awesome! The issue is easily reproducible in our end, will re-test after making these changes ๐Ÿ™ thank you!
6 Views