mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Improve Azure startup time and fix command palette (#5761)
* Improve Azure startup time and fix command palette - Improvement (but not full fix) for #4732 where Azure startup is very slow. This speeds the startup by up to 5 seconds by - Changing from fixed 5 second initial wait time to a promise to check for accounts - Using the accounts changed notification to send a message when accounts are ready. This is usually what will "win out" since Azure seems to load before the Account Providers are set up. - Remove right-click actions from the command palette. - Rename Azure actions so it's clear what they are in the command palette. * Remove coveralls task while investigating how to make optional task * Add void return type
This commit is contained in:
@@ -118,6 +118,33 @@
|
||||
]
|
||||
},
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "azure.resource.signin",
|
||||
"when": "true"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.refreshall",
|
||||
"when": "true"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.selectsubscriptions",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.refresh",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.connectsqlserver",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.connectsqldb",
|
||||
"when": "false"
|
||||
}
|
||||
|
||||
],
|
||||
"view/title": [
|
||||
{
|
||||
"command": "azure.resource.signin",
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
"azure.resource.config.title": "Azure Resource Configuration",
|
||||
"azure.resource.config.filter.description": "The resource filter, each element is an account id, a subscription id and name separated by a slash",
|
||||
"azure.resource.explorer.title": "Azure",
|
||||
"azure.resource.refreshall.title": "Refresh All",
|
||||
"azure.resource.refreshall.title": "Azure: Refresh All Accounts",
|
||||
"azure.resource.refresh.title": "Refresh",
|
||||
"azure.resource.signin.title": "Sign In",
|
||||
"azure.resource.signin.title": "Azure: Sign In",
|
||||
"azure.resource.selectsubscriptions.title": "Select Subscriptions",
|
||||
"azure.resource.connectsqlserver.title": "Connect",
|
||||
"azure.resource.connectsqldb.title": "Add to Servers",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'use strict';
|
||||
|
||||
import { TreeDataProvider, EventEmitter, Event, TreeItem } from 'vscode';
|
||||
import { setInterval, clearInterval } from 'timers';
|
||||
import * as azdata from 'azdata';
|
||||
import { AppContext } from '../../appContext';
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
@@ -16,13 +16,40 @@ import { AzureResourceAccountTreeNode } from './accountTreeNode';
|
||||
import { AzureResourceAccountNotSignedInTreeNode } from './accountNotSignedInTreeNode';
|
||||
import { AzureResourceMessageTreeNode } from '../messageTreeNode';
|
||||
import { AzureResourceContainerTreeNodeBase } from './baseTreeNodes';
|
||||
import { AzureResourceErrorMessageUtil } from '../utils';
|
||||
import { AzureResourceErrorMessageUtil, equals } from '../utils';
|
||||
import { IAzureResourceTreeChangeHandler } from './treeChangeHandler';
|
||||
import { IAzureResourceAccountService } from '../../azureResource/interfaces';
|
||||
import { AzureResourceServiceNames } from '../constants';
|
||||
|
||||
|
||||
export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IAzureResourceTreeChangeHandler {
|
||||
public isSystemInitialized: boolean = false;
|
||||
|
||||
private accountService: IAzureResourceAccountService;
|
||||
private accounts: azdata.Account[];
|
||||
private _onDidChangeTreeData = new EventEmitter<TreeNode>();
|
||||
private loadingAccountsPromise: Promise<void>;
|
||||
|
||||
public constructor(public readonly appContext: AppContext) {
|
||||
if (appContext) {
|
||||
this.hookAccountService(appContext);
|
||||
}
|
||||
}
|
||||
|
||||
private hookAccountService(appContext: AppContext): void {
|
||||
this.accountService = appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService);
|
||||
if (this.accountService) {
|
||||
this.accountService.onDidChangeAccounts((e: azdata.DidChangeAccountsParams) => {
|
||||
// the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change
|
||||
// the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback
|
||||
// this below check short-circuits the infinite callback loop
|
||||
this.setSystemInitialized();
|
||||
if (!equals(e.accounts, this.accounts)) {
|
||||
this.accounts = e.accounts;
|
||||
this.notifyNodeChanged(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async getChildren(element?: TreeNode): Promise<TreeNode[]> {
|
||||
@@ -30,34 +57,16 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
|
||||
return element.getChildren(true);
|
||||
}
|
||||
|
||||
if (!this.isSystemInitialized && !this._loadingTimer) {
|
||||
this._loadingTimer = setInterval(async () => {
|
||||
try {
|
||||
// Call azdata.accounts.getAllAccounts() to determine whether the system has been initialized.
|
||||
await this.appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService).getAccounts();
|
||||
|
||||
// System has been initialized
|
||||
this.isSystemInitialized = true;
|
||||
|
||||
if (this._loadingTimer) {
|
||||
clearInterval(this._loadingTimer);
|
||||
}
|
||||
|
||||
this._onDidChangeTreeData.fire(undefined);
|
||||
} catch (error) {
|
||||
// System not initialized yet
|
||||
this.isSystemInitialized = false;
|
||||
}
|
||||
}, AzureResourceTreeProvider.loadingTimerInterval);
|
||||
|
||||
return [AzureResourceMessageTreeNode.create(AzureResourceTreeProvider.loadingLabel, undefined)];
|
||||
if (!this.isSystemInitialized) {
|
||||
if (!this.loadingAccountsPromise) {
|
||||
this.loadingAccountsPromise = this.loadAccounts();
|
||||
}
|
||||
return [AzureResourceMessageTreeNode.create(localize('azure.resource.tree.treeProvider.loadingLabel', 'Loading ...'), undefined)];
|
||||
}
|
||||
|
||||
try {
|
||||
const accounts = await this.appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService).getAccounts();
|
||||
|
||||
if (accounts && accounts.length > 0) {
|
||||
return accounts.map((account) => new AzureResourceAccountTreeNode(account, this.appContext, this));
|
||||
if (this.accounts && this.accounts.length > 0) {
|
||||
return this.accounts.map((account) => new AzureResourceAccountTreeNode(account, this.appContext, this));
|
||||
} else {
|
||||
return [new AzureResourceAccountNotSignedInTreeNode()];
|
||||
}
|
||||
@@ -66,6 +75,23 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
|
||||
}
|
||||
}
|
||||
|
||||
private async loadAccounts(): Promise<void> {
|
||||
try {
|
||||
this.accounts = await this.appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService).getAccounts();
|
||||
// System has been initialized
|
||||
this.setSystemInitialized();
|
||||
this._onDidChangeTreeData.fire(undefined);
|
||||
} catch (err) {
|
||||
// Skip for now, we can assume that the accounts changed event will eventually notify instead
|
||||
this.isSystemInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
private setSystemInitialized(): void {
|
||||
this.isSystemInitialized = true;
|
||||
this.loadingAccountsPromise = undefined;
|
||||
}
|
||||
|
||||
public get onDidChangeTreeData(): Event<TreeNode> {
|
||||
return this._onDidChangeTreeData.event;
|
||||
}
|
||||
@@ -87,12 +113,4 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
|
||||
public getTreeItem(element: TreeNode): TreeItem | Thenable<TreeItem> {
|
||||
return element.getTreeItem();
|
||||
}
|
||||
|
||||
public isSystemInitialized: boolean = false;
|
||||
|
||||
private _loadingTimer: NodeJS.Timer = undefined;
|
||||
private _onDidChangeTreeData = new EventEmitter<TreeNode>();
|
||||
|
||||
private static readonly loadingLabel = localize('azure.resource.tree.treeProvider.loadingLabel', 'Loading ...');
|
||||
private static readonly loadingTimerInterval = 5000;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as constants from './constants';
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
import { AppContext } from './appContext';
|
||||
import { ApiWrapper } from './apiWrapper';
|
||||
@@ -30,7 +29,6 @@ import { registerAzureResourceCommands } from './azureResource/commands';
|
||||
import { registerAzureResourceDatabaseServerCommands } from './azureResource/providers/databaseServer/commands';
|
||||
import { registerAzureResourceDatabaseCommands } from './azureResource/providers/database/commands';
|
||||
import { AzureResourceTreeProvider } from './azureResource/tree/treeProvider';
|
||||
import { equals } from './azureResource/utils';
|
||||
|
||||
let extensionContext: vscode.ExtensionContext;
|
||||
|
||||
@@ -72,7 +70,6 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
registerAzureServices(appContext);
|
||||
const azureResourceTree = new AzureResourceTreeProvider(appContext);
|
||||
pushDisposable(apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree));
|
||||
registerAccountService(appContext, azureResourceTree);
|
||||
registerCommands(appContext, azureResourceTree);
|
||||
|
||||
return {
|
||||
@@ -113,26 +110,12 @@ async function initAzureAccountProvider(extensionContext: vscode.ExtensionContex
|
||||
|
||||
function registerAzureServices(appContext: AppContext): void {
|
||||
appContext.registerService<AzureResourceService>(AzureResourceServiceNames.resourceService, new AzureResourceService());
|
||||
appContext.registerService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService, new AzureResourceAccountService(appContext.apiWrapper));
|
||||
appContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, new AzureResourceCacheService(extensionContext));
|
||||
appContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, new AzureResourceSubscriptionService());
|
||||
appContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, new AzureResourceSubscriptionFilterService(new AzureResourceCacheService(extensionContext)));
|
||||
appContext.registerService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService, new AzureResourceTenantService());
|
||||
}
|
||||
function registerAccountService(appContext: AppContext, azureResourceTree: AzureResourceTreeProvider): void {
|
||||
let accountService = new AzureResourceAccountService(appContext.apiWrapper);
|
||||
appContext.registerService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService, accountService);
|
||||
let previousAccounts: Array<azdata.Account> = undefined;
|
||||
accountService.onDidChangeAccounts((e: azdata.DidChangeAccountsParams) => {
|
||||
// the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change
|
||||
// the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback
|
||||
// this below check short-circuits the infinite callback loop
|
||||
if (!equals(e.accounts, previousAccounts)) {
|
||||
azureResourceTree.notifyNodeChanged(undefined);
|
||||
}
|
||||
previousAccounts = e.accounts;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function registerCommands(appContext: AppContext, azureResourceTree: AzureResourceTreeProvider): void {
|
||||
registerAzureResourceCommands(appContext, azureResourceTree);
|
||||
|
||||
Reference in New Issue
Block a user