microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.3.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/experimentService/experimentService.ts

181lines · modeblame

88671796RedMickey5 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as https from "https";
5import * as vscode from "vscode";
6import { IExperiment } from "./IExperiment";
7import { PromiseUtil } from "../../common/node/promise";
8import { TelemetryHelper } from "../../common/telemetryHelper";
9import { Telemetry } from "../../common/telemetry";
155e1318JiglioNero5 years ago10import { ExtensionConfigManager } from "../extensionConfigManager";
88671796RedMickey5 years ago11
12export enum ExperimentStatuses {
13ENABLED = "enabled",
14DISABLED = "disabled",
15FAILED = "failed",
16}
17
18export interface ExperimentConfig {
19experimentName: string;
20popCoveragePercent: number;
21enabled: boolean;
22}
23
24export interface ExperimentParameters extends ExperimentConfig {
25[key: string]: any;
26extensionId?: string;
27}
28
29export interface ExperimentResult {
30resultStatus: ExperimentStatuses;
31updatedExperimentParameters: ExperimentParameters;
32error?: Error;
33}
34
35export class ExperimentService implements vscode.Disposable {
36private static instance: ExperimentService;
37
38private readonly endpointURL: string;
39private downloadedExperimentsConfig: Array<ExperimentConfig> | null;
40private experimentsInstances: Map<string, IExperiment>;
41private downloadConfigRequest: Promise<ExperimentConfig[]>;
42private cancellationTokenSource: vscode.CancellationTokenSource;
43
34472878RedMickey5 years ago44public static create(): ExperimentService {
88671796RedMickey5 years ago45if (!ExperimentService.instance) {
46ExperimentService.instance = new ExperimentService();
47}
48
49return ExperimentService.instance;
50}
51
52public async runExperiments(): Promise<void> {
53if (!this.downloadedExperimentsConfig) {
54this.downloadedExperimentsConfig = await this.downloadConfigRequest;
55this.experimentsInstances = await this.initializeExperimentsInstances();
56}
57
58let experimentResults: Array<ExperimentResult> = await Promise.all(
34472878RedMickey5 years ago59this.downloadedExperimentsConfig.map(expConfig => this.executeExperiment(expConfig)),
88671796RedMickey5 years ago60);
61
62this.sendExperimentTelemetry(experimentResults);
63}
64
34472878RedMickey5 years ago65public dispose(): void {
88671796RedMickey5 years ago66this.cancellationTokenSource.cancel();
67this.cancellationTokenSource.dispose();
68}
69
70private constructor() {
34472878RedMickey5 years ago71this.endpointURL =
72"https://microsoft.github.io/vscode-react-native/experiments/experimentsConfig.json";
88671796RedMickey5 years ago73this.cancellationTokenSource = new vscode.CancellationTokenSource();
74this.downloadedExperimentsConfig = null;
75
76this.downloadConfigRequest = this.retryDownloadExperimentsConfig();
77}
78
79private async executeExperiment(expConfig: ExperimentConfig): Promise<ExperimentResult> {
155e1318JiglioNero5 years ago80let curExperimentParameters = ExtensionConfigManager.config.get(expConfig.experimentName);
88671796RedMickey5 years ago81let expInstance = this.experimentsInstances.get(expConfig.experimentName);
82
83let expResult: ExperimentResult;
84if (expInstance && expConfig.enabled) {
85try {
86expResult = await expInstance.run(expConfig, curExperimentParameters);
155e1318JiglioNero5 years ago87ExtensionConfigManager.config.set(
88expConfig.experimentName,
89expResult.updatedExperimentParameters,
90);
88671796RedMickey5 years ago91} catch (err) {
92expResult = {
93resultStatus: ExperimentStatuses.FAILED,
94updatedExperimentParameters: expConfig,
95error: err,
96};
97}
98} else {
99expResult = {
100resultStatus: ExperimentStatuses.DISABLED,
101updatedExperimentParameters: expConfig,
102};
103}
104
105return expResult;
106}
107
108private async retryDownloadExperimentsConfig(retryCount = 60): Promise<ExperimentConfig[]> {
109try {
110return await this.downloadExperimentsConfig();
111} catch (err) {
112if (retryCount < 1 || this.cancellationTokenSource.token.isCancellationRequested) {
113throw err;
114}
115
259c018fYuri Skorokhodov5 years ago116await PromiseUtil.delay(2000);
88671796RedMickey5 years ago117return await this.retryDownloadExperimentsConfig(--retryCount);
118}
119}
120
121private async initializeExperimentsInstances(): Promise<Map<string, IExperiment>> {
122let expInstances = new Map<string, IExperiment>();
123
124if (this.downloadedExperimentsConfig) {
125for (let expConfig of this.downloadedExperimentsConfig) {
126try {
127let expClass = await import(`./experiments/${expConfig.experimentName}`);
34472878RedMickey5 years ago128expInstances.set(expConfig.experimentName, new expClass.default());
88671796RedMickey5 years ago129} catch (err) {
130expConfig.enabled = false;
131}
132}
133}
134
135return expInstances;
136}
137
138private downloadExperimentsConfig(): Promise<ExperimentConfig[]> {
139return new Promise<ExperimentConfig[]>((resolve, reject) => {
34472878RedMickey5 years ago140https
141.get(this.endpointURL, response => {
142let data = "";
143response.setEncoding("utf8");
144response.on("data", (chunk: string) => (data += chunk));
145response.on("end", () => {
146try {
147resolve(JSON.parse(data));
148} catch (err) {
149reject(err);
150}
151});
152response.on("error", reject);
153})
154.on("error", reject);
88671796RedMickey5 years ago155});
156}
157
158private sendExperimentTelemetry(experimentsResults: ExperimentResult[]): void {
159const runExperimentsEvent = TelemetryHelper.createTelemetryEvent("runExperiments");
160
161experimentsResults.forEach(expResult => {
34472878RedMickey5 years ago162if (expResult.resultStatus === ExperimentStatuses.FAILED && expResult.error) {
88671796RedMickey5 years ago163TelemetryHelper.addTelemetryEventErrorProperty(
164runExperimentsEvent,
165expResult.error,
166undefined,
34472878RedMickey5 years ago167`${expResult.updatedExperimentParameters.experimentName}.`,
88671796RedMickey5 years ago168);
169} else {
170TelemetryHelper.addTelemetryEventProperty(
171runExperimentsEvent,
172expResult.updatedExperimentParameters.experimentName,
173expResult.resultStatus,
34472878RedMickey5 years ago174false,
88671796RedMickey5 years ago175);
176}
177});
178
179Telemetry.send(runExperimentsEvent);
180}
181}