launchdarkly / node-server-sdk

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

Multiple client instances #127

Closed amacar closed 5 years ago

amacar commented 6 years ago

Hi,

I am trying to init multiple clients at the same time, but it looks like that only first initialized client works. Is this behavior supported or what is your proposed solution?

Here is a function that identifies a user and adds it to the segment. The user is only created using the first client, for the second call though user is never created. Code:

const identifyUser = async (sdkKey, user, segmentUrl, envName, segmentKey, body) => {
  const client = LaunchDarkly.init(sdkKey, { flushInterval: 1 });
  await client.waitForInitialization();
  client.identify(user);
  await client.flush();
  await launchDarklyAxios.patch(`${segmentUrl + envName}/${segmentKey}`, body);
  client.close();
};

await identifyUser(envKeys[0].sdkKey, user, segmentUrl, envKeys[0].name, segmentKey, body);
await identifyUser(envKeys[1].sdkKey, user, segmentUrl, envKeys[1].name, segmentKey, body);
eli-darkly commented 5 years ago

You are definitely allowed to create multiple client instances— it's rare but we do it in our own integration testing. The first one created shouldn't behave any differently than the others. At first glance I can't see anything wrong with your code. My first guess would have been possibly an error in the SDK key causing the client to be effectively offline, but in that case waitForInitialization() wouldn't have resolved— and if something prevented it from posting events (i.e. the event generated by identify() that contains the user data) then client.flush() should have thrown an error.

Also, just FYI, setting flushInterval: 1 doesn't really make any difference if you're going to manually flush right away and close the client anyway. It doesn't hurt, though.

It might be worthwhile to turn on debug logging as shown below; the SDK will log a debug message whenever it posts event data to LaunchDarkly. My guess is that this will show that the first client sent an event and the second didn't for unknown reasons, so I would still need to dig deeper anyway, but I'm curious.

// turning on debug logging
const winston = require('winston');
const logger = new winston.Logger({
  level: 'debug',
  transports: [ new (winston.transports.Console)() ],
});
const clientOptions = { logger: logger, flushInterval: 1 };
const client = LaunchDarkly.init(sdkKey, clientOptions);
amacar commented 5 years ago

Thank you for quick answer and notes regarding flushInterval, I was just trying every single option. :)

Actually both calls are working ok (that means that sdk key is ok), if I comment one of them. Second one is not working if they are run one after another. If I switch the order then again second one (with different sdk key) is not working. Will try to use debug tomorrow and report here.

Maybe just a question. In docs I didn't find an option to create a user, but just to list, get and delete. Can I try direct call (in this case I will need endpoint + params) without your client since this is the only call that we are using right now.

eli-darkly commented 5 years ago

Actually both calls are working ok (that means that sdk key is ok), if I comment one of them. Second one is not working if they are run one after another. If I switch the order then again second one (with different sdk key) is not working.

That's interesting, and also confusing— it's hard for me to imagine what could produce such behavior, the two instances should be completely independent of each other. There is no global state at all in the SDK.

Can I try direct call [to create a user] (in this case I will need endpoint + params) without your client

Sure. The endpoint is https://events.launchdarkly.com/bulk. Do a POST with the following headers and content:

Content-Type: application/json
Authorization: YOUR_SDK_KEY

[
  {
    "kind": "identify",
    "key": "KEY_OF_USER",
    "creationDate": CURRENT_UNIX_TIME_MILLISECONDS,
    "user": { ... all user properties here ... }
  }
]

(Note the square brackets around the object - this endpoint can be used for posting multiple events so it takes a JSON array.)

eli-darkly commented 5 years ago

Also, here's a dumb question: in your code, are you entirely sure that both of the calls to identifyUser are actually executing?

amacar commented 5 years ago

I tested a little more and I found that problem is that I am creating a user with the same key in all environments. If I change the key of user per environment then my code works. So you are not allowing the same users in different environments? Are users only unique per project not per environment?

eli-darkly commented 5 years ago

How exactly are you determining whether the test worked? I mean, can you tell me the specific steps that you're doing to look for the two users? I just want to make sure I'm not overlooking anything obvious, because this situation still isn't making much sense to me.

You are definitely allowed to have the same user keys in different environments - those are entirely separate spaces for users as far as LaunchDarkly is concerned. It wouldn't really make sense for them to be shared, because you might be for instance using a unique identifier from a database as a user key, and different instances of an application (e.g. production vs. staging environments) would presumably have separate databases so the same key could have a different meaning.

amacar commented 5 years ago

This is not connected with lib anymore because I am testing with Postman and direct call to API endpoint so I can close this "issue". However, looks like that endpoint is behaving strange. Sometimes it just doesn't create a user (response is only 202 Accepted) so it is not connected with using the same keys for a user (as I thought before), but I can't find where the real problem lies.