Skip to content

Commit

Permalink
allow the configuration of executors memory during deploy (#646)
Browse files Browse the repository at this point in the history
- Add an app update command
- Allow memory config during app registration / update
  • Loading branch information
maxdml authored Oct 15, 2024
1 parent 1584064 commit ea3cbb0
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 25 deletions.
1 change: 1 addition & 0 deletions packages/dbos-cloud/applications/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { registerApp } from "./register-app.js";
export { updateApp } from "./update-app.js";
export { listApps } from "./list-apps.js";
export { deleteApp } from "./delete-app.js";
export { deployAppCode } from "./deploy-app-code.js";
Expand Down
57 changes: 41 additions & 16 deletions packages/dbos-cloud/applications/register-app.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
import axios, { AxiosError } from "axios";
import { handleAPIErrors, getCloudCredentials, getLogger, isCloudAPIErrorResponse, retrieveApplicationName, CloudAPIErrorResponse, retrieveApplicationLanguage, DBOSCloudCredentials } from "../cloudutils.js";
import {
handleAPIErrors,
getCloudCredentials,
getLogger,
isCloudAPIErrorResponse,
retrieveApplicationName,
CloudAPIErrorResponse,
retrieveApplicationLanguage,
DBOSCloudCredentials,
} from "../cloudutils.js";
import chalk from "chalk";

export async function registerApp(dbname: string, host: string, enableTimetravel: boolean = false, appName?: string, userCredentials?: DBOSCloudCredentials): Promise<number> {
type RegisterAppRequest = {
name: string;
database: string;
language: string;
provenancedb?: string;
executors_memory_mib?: number;
};

export async function registerApp(
dbname: string,
host: string,
enableTimetravel: boolean = false,
appName?: string,
executorsMemoryMib?: number,
userCredentials?: DBOSCloudCredentials
): Promise<number> {
const logger = getLogger();
if (!userCredentials) {
userCredentials = await getCloudCredentials(host, logger);
Expand All @@ -17,21 +41,22 @@ export async function registerApp(dbname: string, host: string, enableTimetravel

try {
logger.info(`Registering application: ${appName}`);
const register = await axios.put(
`https://${host}/v1alpha1/${userCredentials.organization}/applications`,
{
name: appName,
database: dbname,
language: appLanguage,
provenancedb: enableTimetravel ? dbname : "",
const body: RegisterAppRequest = {
name: appName,
database: dbname,
language: appLanguage,
provenancedb: enableTimetravel ? dbname : "",
};
if (executorsMemoryMib) {
body.executors_memory_mib = executorsMemoryMib;
}

const register = await axios.put(`https://${host}/v1alpha1/${userCredentials.organization}/applications`, body, {
headers: {
"Content-Type": "application/json",
Authorization: bearerToken,
},
{
headers: {
"Content-Type": "application/json",
Authorization: bearerToken,
},
}
);
});
const uuid = register.data as string;
logger.info(`${appName} ID: ${uuid}`);
logger.info(`Successfully registered ${appName}!`);
Expand Down
2 changes: 2 additions & 0 deletions packages/dbos-cloud/applications/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type Application = {
Status: string;
Version: string;
AppURL: string;
ExecutorsMemoryMib: number;
};

export function prettyPrintApplication(app: Application) {
Expand All @@ -30,6 +31,7 @@ export function prettyPrintApplicationVersion(version: ApplicationVersion) {
console.log(`Creation Timestamp: ${version.CreationTime}`);
}

// Either types.ts should be in the parent folder, or UserDBInstance should be in databases/types.ts
export interface UserDBInstance {
readonly PostgresInstanceName: string;
readonly Status: string;
Expand Down
42 changes: 42 additions & 0 deletions packages/dbos-cloud/applications/update-app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import axios, { AxiosError } from "axios";
import { handleAPIErrors, getCloudCredentials, getLogger, isCloudAPIErrorResponse, retrieveApplicationName, DBOSCloudCredentials } from "../cloudutils.js";

export async function updateApp(host: string, appName?: string, executorsMemoryMib?: number, userCredentials?: DBOSCloudCredentials): Promise<number> {
const logger = getLogger();
if (!userCredentials) {
userCredentials = await getCloudCredentials(host, logger);
}
const bearerToken = "Bearer " + userCredentials.token;

appName = appName || retrieveApplicationName(logger);
if (!appName) {
return 1;
}

try {
logger.info(`Updating application: ${appName}`);
await axios.patch(
`https://${host}/v1alpha1/${userCredentials.organization}/applications/${appName}`,
{
executors_memory_mib: executorsMemoryMib,
},
{
headers: {
"Content-Type": "application/json",
Authorization: bearerToken,
},
}
);
logger.info(`Successfully updated ${appName}!`);
return 0;
} catch (e) {
const errorLabel = `Failed to update application ${appName}`;
const axiosError = e as AxiosError;
if (isCloudAPIErrorResponse(axiosError.response?.data)) {
handleAPIErrors(errorLabel, axiosError);
} else {
logger.error(`${errorLabel}: ${(e as Error).message}`);
}
return 1;
}
}
28 changes: 19 additions & 9 deletions packages/dbos-cloud/cli.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env node

import { registerApp, listApps, deleteApp, deployAppCode, getAppLogs } from "./applications/index.js";
import { registerApp, updateApp, listApps, deleteApp, deployAppCode, getAppLogs } from "./applications/index.js";
import { Command } from "commander";
import { login } from "./users/login.js";
import { registerUser } from "./users/register.js";
Expand Down Expand Up @@ -113,8 +113,19 @@ applicationCommands
.argument("[string]", "application name (Default: name from package.json)")
.requiredOption("-d, --database <string>", "Specify a Postgres database instance for this application")
.option("--enable-timetravel", "Enable time travel for the application", false)
.action(async (appName: string | undefined, options: { database: string, enableTimetravel: boolean }) => {
const exitCode = await registerApp(options.database, DBOSCloudHost, options.enableTimetravel, appName);
.option("--executors-memory-mib <number>", "Specify the memory in MiB for the executors of this application")
.action(async (appName: string | undefined, options: { database: string; enableTimetravel: boolean; executorsMemoryMib?: number }) => {
const exitCode = await registerApp(options.database, DBOSCloudHost, options.enableTimetravel, appName, options.executorsMemoryMib);
process.exit(exitCode);
});

applicationCommands
.command("update")
.description("Update this application")
.argument("[string]", "application name (Default: name from package.json)")
.option("--executors-memory-mib <number>", "Specify the memory in MiB for the executors of this application")
.action(async (appName: string | undefined, options: { executorsMemoryMib?: number }) => {
const exitCode = await updateApp(DBOSCloudHost, appName, options.executorsMemoryMib);
process.exit(exitCode);
});

Expand All @@ -126,7 +137,7 @@ applicationCommands
.option("-d, --database <string>", "Specify a Postgres database instance for this application. This cannot be changed after the application is first deployed.")
.option("--enable-timetravel", "Enable time travel for the application. This cannot be changed after the application is first deployed.", false)
.option("--verbose", "Verbose log of deployment step")
.action(async (appName: string | undefined, options: { verbose?: boolean, previousVersion?: string, database?: string, enableTimetravel: boolean }) => {
.action(async (appName: string | undefined, options: { verbose?: boolean; previousVersion?: string; database?: string; enableTimetravel: boolean }) => {
const exitCode = await deployAppCode(DBOSCloudHost, false, options.previousVersion ?? null, options.verbose ?? false, null, appName, options.database, options.enableTimetravel);
process.exit(exitCode);
});
Expand Down Expand Up @@ -285,7 +296,7 @@ databaseCommands
.option("-W, --password <string>", "Specify password for the dbosadmin user")
.option("--enable-timetravel", "Enable time travel on the linked database", false)
.option("--supabase-ref <string>", "Link a Supabase database")
.action(async (dbname: string, options: { hostname: string; port: string; password: string | undefined; enableTimetravel: boolean; supabaseRef: string | undefined}) => {
.action(async (dbname: string, options: { hostname: string; port: string; password: string | undefined; enableTimetravel: boolean; supabaseRef: string | undefined }) => {
if (!options.password) {
options.password = prompt("Password for the dbosadmin user: ", { echo: "*" });
}
Expand All @@ -307,28 +318,27 @@ databaseCommands
.description(`Load cloud database connection information into ${dbosConfigFilePath}`)
.argument("[name]", "database instance name")
.option("-W, --password <string>", "Specify the database user password")
.action(async (dbname: string | undefined, options: { password: string | undefined; }) => {
.action(async (dbname: string | undefined, options: { password: string | undefined }) => {
if (!options.password) {
options.password = prompt("Database Password (must contain at least 8 characters): ", { echo: "*" });
}
const exitCode = await connect(DBOSCloudHost, dbname, options.password, false);
process.exit(exitCode);
});

databaseCommands
databaseCommands
.command("local")
.description(`Configure ${dbosConfigFilePath} to use a DBOS Cloud database for local development`)
.argument("[name]", "database instance name")
.option("-W, --password <string>", "Specify the database user password")
.action(async (dbname: string | undefined, options: { password: string | undefined; }) => {
.action(async (dbname: string | undefined, options: { password: string | undefined }) => {
if (!options.password) {
options.password = prompt("Database Password (must contain at least 8 characters): ", { echo: "*" });
}
const exitCode = await connect(DBOSCloudHost, dbname, options.password, true);
process.exit(exitCode);
});


/////////////////////
/* USER DASHBOARDS */
/////////////////////
Expand Down

0 comments on commit ea3cbb0

Please sign in to comment.