Skip to content

Commit

Permalink
[Main][Task]29519574: Update AISKU Light to better handle Init Promise (
Browse files Browse the repository at this point in the history
#2416)

* update aisku light init with promise

* udpate

* update
  • Loading branch information
Karlie-777 authored Sep 19, 2024
1 parent 8628bba commit 5515866
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 191 deletions.
61 changes: 56 additions & 5 deletions AISKULight/Tests/Unit/src/dynamicconfig.tests.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AITestClass, Assert } from "@microsoft/ai-test-framework";
import { AITestClass, Assert, PollingAssert } from "@microsoft/ai-test-framework";
import { IConfig } from "@microsoft/applicationinsights-common";
import { IConfiguration, newId } from "@microsoft/applicationinsights-core-js";
import { ApplicationInsights } from "../../../src/index";
import { IConfiguration, isString, newId } from "@microsoft/applicationinsights-core-js";
import { ApplicationInsights, ISenderConfig } from "../../../src/index";
import { createAsyncResolvedPromise } from "@nevware21/ts-async";

export class ApplicationInsightsDynamicConfigTests extends AITestClass {
private static readonly _instrumentationKey = "b7170927-2d1c-44f1-acec-59f4e1751c11";
Expand All @@ -10,6 +11,7 @@ export class ApplicationInsightsDynamicConfigTests extends AITestClass {
private _sessionPrefix: string = newId();
private _config: IConfiguration & IConfig;
static registerTests: any;
private _ctx: any;

constructor(testName?: string) {
super(testName || "AISKU Dynamic Config");
Expand All @@ -27,6 +29,7 @@ export class ApplicationInsightsDynamicConfigTests extends AITestClass {
this._config = this._getTestConfig(this._sessionPrefix);

this._ai = new ApplicationInsights(this._config);
this._ctx = {};
} catch (e) {
console.error("Failed to initialize", e);
}
Expand All @@ -37,6 +40,7 @@ export class ApplicationInsightsDynamicConfigTests extends AITestClass {
// force unload
this._ai.unload(false);
}
this._ctx = null;

console.log("* testCleanup(" + (AITestClass.currentTestInfo ? AITestClass.currentTestInfo.name : "<null>") + ")");
}
Expand Down Expand Up @@ -72,20 +76,67 @@ export class ApplicationInsightsDynamicConfigTests extends AITestClass {
Assert.equal(expectedLoggingLevel, details.cfg.diagnosticLogInterval, "Expect the diagnosticLogInterval to be set");
});

Assert.equal(1, onChangeCalled, "OnCfgChange was not called");
Assert.equal(1, onChangeCalled, "OnCfgChange was called once");

expectedIkey = "newIkey";
expectedConnectionString = `InstrumentationKey=${expectedIkey}`;
config.connectionString = expectedConnectionString;
Assert.equal(1, onChangeCalled, "OnCfgChange was called");
this.clock.tick(1);
Assert.equal(2, onChangeCalled, "OnCfgChange was not called");
Assert.equal(3, onChangeCalled, "OnCfgChange was called again");
Assert.equal("newIkey", config.instrumentationKey);

//Remove the handler
handler.rm();
}
});


this.testCaseAsync({
name: "Init: init with cs promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {

// unload previous one first
let oriInst = this._ai;
if (oriInst && oriInst.unload) {
// force unload
oriInst.unload(false);
}

this._config = this._getTestConfig(this._sessionPrefix);
let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");
this._config.connectionString = csPromise;
this._config.initTimeOut= 80000;
this._ctx.csPromise = csPromise;


let init = new ApplicationInsights(this._config);
this._ai = init;
let config = this._ai.config;


}].concat(PollingAssert.createPollingAssert(() => {
let csPromise = this._ctx.csPromise;
let config = this._ai.config;
let ikey = config.instrumentationKey;

if (csPromise.state === "resolved" && isString(ikey)) {
Assert.equal("testIkey", config.instrumentationKey, "ikey should be set");
Assert.equal("testUrl/v2/track", config.endpointUrl ,"endpoint shoule be set");
let sender = this._ai.getPlugin("AppInsightsChannelPlugin").plugin;
let senderConfig = sender["_senderConfig"] as ISenderConfig;
let senderIkey = senderConfig.instrumentationKey;
Assert.equal("testIkey", senderIkey, "sender ikey is set from connection string");
let senderUrl = senderConfig.endpointUrl;
Assert.equal("testUrl/v2/track", senderUrl, "sender endpoint url is set from connection string");

return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
}

public addApiTests(): void {
Expand Down
14 changes: 10 additions & 4 deletions AISKULight/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,24 @@ import {
ITelemetryInitializerHandler, ITelemetryItem, ITelemetryPlugin, ITelemetryUnloadState, IUnloadHook, UnloadHandler, WatcherFunction,
cfgDfValidate, createDynamicConfig, onConfigChange, proxyFunctions
} from "@microsoft/applicationinsights-core-js";
import { IPromise, createAsyncPromise, doAwaitResponse } from "@nevware21/ts-async";
import { IPromise, createSyncPromise, doAwaitResponse } from "@nevware21/ts-async";
import { isNullOrUndefined, isPromiseLike, isString, objDefine, throwError } from "@nevware21/ts-utils";

const UNDEFINED_VALUE: undefined = undefined;
const defaultConfigValues: IConfigDefaults<IConfiguration> = {
diagnosticLogInterval: cfgDfValidate(_chkDiagLevel, 10000)
diagnosticLogInterval: cfgDfValidate(_chkDiagLevel, 10000),
connectionString: UNDEFINED_VALUE,
endpointUrl: UNDEFINED_VALUE,
instrumentationKey: UNDEFINED_VALUE,
extensionConfig: {}
};

function _chkDiagLevel(value: number) {
// Make sure we have a value > 0
return value && value > 0;
}


/**
* @export
* @class ApplicationInsights
Expand Down Expand Up @@ -80,7 +86,7 @@ export class ApplicationInsights {
let configCs = _config.connectionString;

if (isPromiseLike(configCs)) {
let ikeyPromise = createAsyncPromise<string>((resolve, reject) => {
let ikeyPromise = createSyncPromise<string>((resolve, reject) => {
doAwaitResponse(configCs, (res) => {
let curCs = res.value;
let ikey = _config.instrumentationKey;
Expand All @@ -95,7 +101,7 @@ export class ApplicationInsights {

});

let urlPromise = createAsyncPromise<string>((resolve, reject) => {
let urlPromise = createSyncPromise<string>((resolve, reject) => {
doAwaitResponse(configCs, (res) => {
let curCs = res.value;
let url = _config.endpointUrl;
Expand Down
22 changes: 10 additions & 12 deletions channels/applicationinsights-channel-js/src/Sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,15 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
}
});

// Only update the endpoint if the original config !== the current config
// This is so any redirect endpointUrl is not overwritten
if (_orgEndpointUrl !== senderConfig.endpointUrl) {
if (_orgEndpointUrl) {
// TODO: add doc to remind users to flush before changing endpoint, otherwise all unsent payload will be sent to new endpoint
}
_endpointUrl = _orgEndpointUrl = senderConfig.endpointUrl;
}

// or is not string
if (core.activeStatus() === ActiveStatus.PENDING) {
// waiting for core promises to be resolved
Expand All @@ -291,18 +300,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
} else if (core.activeStatus() === ActiveStatus.ACTIVE) {
// core status changed from pending to other status
_self.resume();

}



// Only update the endpoint if the original config !== the current config
// This is so any redirect endpointUrl is not overwritten
if (_orgEndpointUrl !== senderConfig.endpointUrl) {
if (_orgEndpointUrl) {
// TODO: add doc to remind users to flush before changing endpoint, otherwise all unsent payload will be sent to new endpoint
}
_endpointUrl = _orgEndpointUrl = senderConfig.endpointUrl;

}

if (_customHeaders && _customHeaders !== senderConfig.customHeaders) {
Expand Down
Loading

0 comments on commit 5515866

Please sign in to comment.