-
Notifications
You must be signed in to change notification settings - Fork 103
feat: update connectionString appName param - [MCP-68] #406
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
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
src/telemetry/telemetry.ts
Outdated
|
||
private constructor( | ||
private readonly session: Session, | ||
private readonly userConfig: UserConfig, | ||
private readonly commonProperties: CommonProperties, | ||
{ eventCache, getRawMachineId }: { eventCache: EventCache; getRawMachineId: () => Promise<string> } | ||
{ eventCache }: { eventCache: EventCache } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think it'd still be good to pass getDeviceIdForConnection
for explicit DI. It also helps us avoid mocking the file which is a bit of JavaScript magic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done! thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's important in my opinion to avoid double device ID resolution
src/helpers/connectionOptions.ts
Outdated
} | ||
|
||
const deviceId = components.deviceId || (await getDeviceIdForConnection()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we shouldn't end up awaiting device ID a second time, can we organize it so this device ID gets passed from one point of entry and we never fallback to this function? deviceId
doesn't get passed in connectToMongoDB
right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored this quite a bit into a singleton so that we avoid double resolution, let me know what you think and if I'm missing any gaps!
should be ready for review |
This reverts commit ae1d6d0.
@@ -30,8 +31,8 @@ export const LogId = { | |||
telemetryEmitStart: mongoLogId(1_002_003), | |||
telemetryEmitSuccess: mongoLogId(1_002_004), | |||
telemetryMetadataError: mongoLogId(1_002_005), | |||
telemetryDeviceIdFailure: mongoLogId(1_002_006), | |||
telemetryDeviceIdTimeout: mongoLogId(1_002_007), | |||
deviceIdResolutionError: mongoLogId(1_002_006), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very nit: we can still keep the telemetry
prefix since this is still what it's related to (and we have this prefix group pattern right now)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but now resolution could fail upon connection tool since this will now be used in two places, no?
src/helpers/deviceId.ts
Outdated
this.startDeviceIdCalculation(); | ||
} | ||
|
||
/** | ||
* Initializes the DeviceIdService singleton with a logger. | ||
* A separated init method is used to use a single instance of the logger. | ||
* @param logger - The logger instance to use | ||
* @returns The DeviceIdService instance | ||
*/ | ||
public static init(logger: LoggerBase, timeout?: number): DeviceIdService { | ||
if (DeviceIdService.instance) { | ||
return DeviceIdService.instance; | ||
} | ||
DeviceIdService.instance = new DeviceIdService(logger, timeout ?? DEVICE_ID_TIMEOUT); | ||
return DeviceIdService.instance; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I generally prefer to avoid side-effects in constructors i.e. this.startDeviceIdCalculation()
Since we already have an init
pattern, we could make this constructor private and have one create(...)
will also call the startDeviceIdCalculation();
after creating it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Telemetry service is example of that
static create( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool! I think there's no harm in clarifying this one, but bundling it with your comment below are yo suggesting to do something like telemetry but still maintain a singleton? or just use the same approach and inject the logger
object on getDeviceId
calls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either is fine I think, we can also have a late setter for the logger
src/helpers/deviceId.ts
Outdated
/** | ||
* Checks if the DeviceIdService is initialized. | ||
* @returns True if the DeviceIdService is initialized, false otherwise | ||
*/ | ||
public static isInitialized(): boolean { | ||
return DeviceIdService.instance !== undefined; | ||
} | ||
|
||
/** | ||
* Gets the singleton instance of DeviceIdService. | ||
* @returns The DeviceIdService instance | ||
*/ | ||
public static getInstance(): DeviceIdService { | ||
if (!DeviceIdService.instance) { | ||
throw new Error("DeviceIdService not initialized"); | ||
} | ||
return DeviceIdService.instance; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this singleton instance pattern discourages explicit dependency injection which makes it too easy to end up accessing this service prematurely, thus needing these checks to make sure it's initialized. I get it from perspective of only doing the resolution once so we could still keep the static instance as far as create
goes and maybe throw an error if someone tries to re-create the service.
But other than that, the getInstance
is only used in tests right now and I think for that it'd have been preferable to create the DeviceIdService
inside the test and pass it to whatever is being tested instead
this.abortController = new AbortController(); | ||
this.deviceIdPromise = this.calculateDeviceId(); | ||
// start the promise upon setup | ||
void this.deviceIdPromise; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the promise is already "started" from the function being called, this doesn't do anything
* Sets up the device ID calculation promise and abort controller. | ||
*/ | ||
private setup(): void { | ||
this.abortController = new AbortController(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it'd be good to have the abortcontroller defined inside the calculateDeviceId
as it's directly tied to it
} | ||
|
||
public static create(logger: LoggerBase, timeout?: number): DeviceId { | ||
if (this.instance) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice! yeah this is what I meant. more radically, we can also throw an error to enforce that this creation is only done ever
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool! in that case I guess we'd make get()
static so that anyone can get the device Id
} | ||
|
||
try { | ||
const deviceId = await getDeviceId({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getDeviceId
already does plenty of error handling, including the abort error. I don't think this try/catch
will ever catch anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it automatically assign unknown upon error? If so we can remove
this.commonProperties.is_container_env = containerEnv; | ||
|
||
this.isBufferingEvents = false; | ||
} | ||
|
||
public async close(): Promise<void> { | ||
this.deviceIdAbortController.abort(); | ||
this.isBufferingEvents = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would this.deviceId.close
make sense here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it to index.ts so I'm closing it there as well, makes sense?
options.abortSignal?.addEventListener("abort", () => { | ||
clearTimeout(timeout); | ||
const abortError = new Error("Aborted"); | ||
abortError.name = "AbortError"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a real error that can get thrown? pretty sure this is handled by the getDeviceId
function's try/catch so would never reach our own code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed - this is an autogen test that I missed to remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than above, changes look good to me 🙂 feel free to go ahead as you see fit.
Proposed changes
appName--deviceId--clientName
Checklist