From 3ad011377e595cf3e280e345034d9d5558b3552c Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 9 Oct 2024 16:44:16 -0500 Subject: [PATCH] DHE worker settings (#79-2) --- package.json | 43 ++++++++++++++++++++++++- src/controllers/ExtensionController.ts | 1 + src/dh/dhe.ts | 23 ++++++++++---- src/services/ConfigService.ts | 44 ++++++++++++-------------- src/services/DheService.ts | 19 +++++++++++ src/types/commonTypes.d.ts | 14 ++++++-- 6 files changed, 112 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index bde005da..b3874634 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,48 @@ "description": "List of Deephaven Enterprise servers that the extension can connect to.", "type": "array", "items": { - "type": "string" + "anyOf": [ + { + "type": "string", + "description": "Deephaven Enterprise server URL" + }, + { + "type": "object", + "description": "Deephaven Enterprise server config", + "properties": { + "url": { + "type": "string", + "description": "Deephaven Enterprise server URL" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Optional label for the server" + }, + "experimentalWorkerConfig": { + "type": "object", + "description": "(experimental) Worker configuration used when creating new connections to the server", + "properties": { + "dbServerName": { + "type": "string" + }, + "heapSize": { + "type": "number" + }, + "jvmArgs": { + "type": "string" + }, + "jvmProfile": { + "type": "string" + }, + "scriptLanguage": { + "type": "string" + } + } + } + } + } + ] }, "default": [] } diff --git a/src/controllers/ExtensionController.ts b/src/controllers/ExtensionController.ts index 97ced42b..62065670 100644 --- a/src/controllers/ExtensionController.ts +++ b/src/controllers/ExtensionController.ts @@ -311,6 +311,7 @@ export class ExtensionController implements Disposable { ); this._dheServiceFactory = DheService.factory( + this._config, this._coreCredentialsCache, this._dheClientCache, this._dheCredentialsCache, diff --git a/src/dh/dhe.ts b/src/dh/dhe.ts index 527110d4..44c88771 100644 --- a/src/dh/dhe.ts +++ b/src/dh/dhe.ts @@ -11,6 +11,7 @@ import type { IdeURL, QuerySerial, UniqueID, + WorkerConfig, WorkerInfo, WorkerURL, } from '../types'; @@ -116,6 +117,7 @@ export function findQueryConfigForSerial( * Create a query of type `InteractiveConsole`. * @param tagId Unique tag id to include in the query name. * @param dheClient The DHE client to use to create the query. + * @param workerConfig Worker configuration overrides. * @param consoleType The type of console to create. * @returns A promise that resolves to the serial of the created query. Note * that this will resolve before the query is actually ready to use. Use @@ -124,6 +126,7 @@ export function findQueryConfigForSerial( export async function createInteractiveConsoleQuery( tagId: UniqueID, dheClient: EnterpriseClient, + workerConfig: WorkerConfig = {}, consoleType?: ConsoleType ): Promise { const userInfo = await dheClient.getUserInfo(); @@ -137,13 +140,22 @@ export async function createInteractiveConsoleQuery( ]); const name = `IC - VS Code - ${tagId}`; - const dbServerName = dbServers[0]?.name ?? 'Query 1'; - const heapSize = queryConstants.pqDefaultHeap; - const jvmProfile = serverConfigValues.jvmProfileDefault; + const dbServerName = + workerConfig?.dbServerName ?? dbServers[0]?.name ?? 'Query 1'; + const heapSize = workerConfig?.heapSize ?? queryConstants.pqDefaultHeap; + // TODO: deephaven/vscode-deephaven/issues/153 to update this to secure websocket + // connection and remove the http.websockets property + const jvmArgs = workerConfig?.jvmArgs + ? `'-Dhttp.websockets=true' ${workerConfig.jvmArgs}` + : '-Dhttp.websockets=true'; + const jvmProfile = + workerConfig?.jvmProfile ?? serverConfigValues.jvmProfileDefault; const scriptLanguage = + workerConfig?.scriptLanguage ?? serverConfigValues.scriptSessionProviders?.find( p => p.toLocaleLowerCase() === consoleType - ) ?? 'Python'; + ) ?? + 'Python'; const workerKind = serverConfigValues.workerKinds?.[0]?.name; const timeZone = @@ -164,8 +176,7 @@ export async function createInteractiveConsoleQuery( dbServerName, heapSize: heapSize, scheduling, - // TODO: deephaven/vscode-deephaven/issues/153 to update this to secure websocket connection - jvmArgs: '-Dhttp.websockets=true', + jvmArgs, jvmProfile, scriptLanguage, workerKind, diff --git a/src/services/ConfigService.ts b/src/services/ConfigService.ts index d90d16ad..bc0f9124 100644 --- a/src/services/ConfigService.ts +++ b/src/services/ConfigService.ts @@ -29,17 +29,7 @@ function getCoreServers(): CoreConnectionConfig[] { logger.info('Core servers:', JSON.stringify(expandedConfig)); return expandedConfig - .filter(server => { - try { - // Filter out any invalid server configs to avoid crashing the extension - // further upstream. - new URL(server.url); - return true; - } catch (err) { - logger.error(err, server.url); - return false; - } - }) + .filter(hasValidURL) .map(server => ({ ...server, url: new URL(server.url) })); } @@ -49,25 +39,33 @@ function getEnterpriseServers(): EnterpriseConnectionConfig[] { [] ); - const expandedConfig = config.map(url => ({ url })); + // Expand each server config to a full `ConnectionConfig` object. + const expandedConfig = config.map(server => + typeof server === 'string' ? { url: server } : server + ); logger.info('Enterprise servers:', JSON.stringify(expandedConfig)); return expandedConfig - .filter(server => { - try { - // Filter out any invalid server configs to avoid crashing the extension - // further upstream. - new URL(server.url); - return true; - } catch (err) { - logger.error(err, server.url); - return false; - } - }) + .filter(hasValidURL) .map(server => ({ ...server, url: new URL(server.url) })); } +/** + * Attempt to parse a `url` string prop into a `URL` object. + * @param objectWithUrl An object with a `url` string prop. + * @returns `true` if the `url` prop is a valid URL, `false` otherwise. + */ +function hasValidURL({ url }: { url: string }): boolean { + try { + new URL(url); + return true; + } catch (err) { + logger.error(err, url); + return false; + } +} + // eslint-disable-next-line @typescript-eslint/naming-convention export const ConfigService: IConfigService = { getCoreServers, diff --git a/src/services/DheService.ts b/src/services/DheService.ts index d7dc26f0..b8790297 100644 --- a/src/services/DheService.ts +++ b/src/services/DheService.ts @@ -9,11 +9,13 @@ import { WorkerURL, type ConsoleType, type IAsyncCacheService, + type IConfigService, type IDheService, type IDheServiceFactory, type Lazy, type QuerySerial, type UniqueID, + type WorkerConfig, type WorkerInfo, } from '../types'; import { URLMap } from './URLMap'; @@ -42,6 +44,7 @@ export class DheService implements IDheService { * @returns A factory function that can be used to create DheService instances. */ static factory = ( + configService: IConfigService, coreCredentialsCache: URLMap>, dheClientCache: IAsyncCacheService, dheCredentialsCache: URLMap, @@ -51,6 +54,7 @@ export class DheService implements IDheService { create: (serverUrl: URL): IDheService => new DheService( serverUrl, + configService, coreCredentialsCache, dheClientCache, dheCredentialsCache, @@ -65,12 +69,14 @@ export class DheService implements IDheService { */ private constructor( serverUrl: URL, + configService: IConfigService, coreCredentialsCache: URLMap>, dheClientCache: IAsyncCacheService, dheCredentialsCache: URLMap, dheJsApiCache: IAsyncCacheService ) { this.serverUrl = serverUrl; + this._config = configService; this._coreCredentialsCache = coreCredentialsCache; this._dheClientCache = dheClientCache; this._dheCredentialsCache = dheCredentialsCache; @@ -81,6 +87,7 @@ export class DheService implements IDheService { private _clientPromise: Promise | null = null; private _isConnected: boolean = false; + private readonly _config: IConfigService; private readonly _coreCredentialsCache: URLMap< Lazy >; @@ -152,6 +159,17 @@ export class DheService implements IDheService { } }; + /** + * Get the config for creating new workers. + * @returns Worker config or undefined if not found. + */ + getWorkerConfig = (): WorkerConfig | undefined => { + return this._config + .getEnterpriseServers() + .find(server => server.url.toString() === this.serverUrl.toString()) + ?.experimentalWorkerConfig; + }; + /** * Get worker info for given worker URL. * @param workerUrl Worker URL to get info for. @@ -210,6 +228,7 @@ export class DheService implements IDheService { const querySerial = await createInteractiveConsoleQuery( tagId, dheClient, + this.getWorkerConfig(), consoleType ); this._querySerialSet.add(querySerial); diff --git a/src/types/commonTypes.d.ts b/src/types/commonTypes.d.ts index 8a8940c7..77347026 100644 --- a/src/types/commonTypes.d.ts +++ b/src/types/commonTypes.d.ts @@ -28,11 +28,13 @@ export interface CoreConnectionConfig { } export type EnterpriseConnectionConfigStored = - Brand<'EnterpriseConnectionConfigStored'>; + | Brand<'EnterpriseConnectionConfigStored'> + | { url: string; label?: string; experimentalWorkerConfig?: WorkerConfig }; export interface EnterpriseConnectionConfig { - label?: string; url: URL; + label?: string; + experimentalWorkerConfig?: WorkerConfig; } export type ServerConnectionConfig = @@ -40,6 +42,14 @@ export type ServerConnectionConfig = | EnterpriseConnectionConfig | URL; +export interface WorkerConfig { + dbServerName?: string; + heapSize?: number; + jvmArgs?: string; + jvmProfile?: string; + scriptLanguage?: string; +} + export interface ConnectionState { readonly isConnected: boolean; readonly serverUrl: URL;