Skip to content

Commit

Permalink
WIP: Degrade more gracefully when the droplet limit is reached
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Schwartz committed May 4, 2022
1 parent 4664384 commit 1b48be6
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/server_manager/cloud/digitalocean_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type Account = Readonly<{
uuid: string;
email_verified: boolean;
status: string;
droplet_limit: number;
}>;

// Reference:
Expand Down
2 changes: 2 additions & 0 deletions src/server_manager/model/digitalocean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,6 @@ export interface Account {
// Creates a server and returning it when it becomes active (i.e. the server has
// created, not necessarily once shadowbox installation has finished).
createServer(region: Region, name: string): Promise<ManagedServer>;

hasReachedLimit(): Promise<boolean>;
}
11 changes: 11 additions & 0 deletions src/server_manager/web_app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,17 @@ export class App {
return;
}

try {
if (await digitalOceanAccount.hasReachedLimit()) {
this.appRoot.showError(
'Your DigitalOcean account has reached its Droplet limit. You can request an increase at https://cloud.digitalocean.com/account/team/droplet_limit_increase'
);
return;
}
} catch (e) {
console.error('Failed to check droplet limit status', e);
}

try {
const regionPicker = this.appRoot.getAndShowRegionPicker();
const map = await this.digitalOceanRetry(() => {
Expand Down
15 changes: 14 additions & 1 deletion src/server_manager/web_app/digitalocean_account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,18 @@ export class DigitalOceanAccount implements digitalocean.Account {

async getStatus(): Promise<digitalocean.Status> {
const account = await this.digitalOcean.getAccount();
if (account.status === 'active') {
if (account.status !== 'locked') {
return digitalocean.Status.ACTIVE;
}
if (!account.email_verified) {
return digitalocean.Status.EMAIL_UNVERIFIED;
}
const servers = await this.digitalOcean.getDroplets();
if (servers.length > 0) {
// The account is locked, but it has droplets so it must have
// been activated with billing information.
return digitalocean.Status.ACTIVE;
}
return digitalocean.Status.MISSING_BILLING_INFORMATION;
}

Expand All @@ -67,6 +73,13 @@ export class DigitalOceanAccount implements digitalocean.Account {
}));
}

// Returns true if there is no more room for additional Droplets.
async hasReachedLimit(): Promise<boolean> {
const account = this.digitalOcean.getAccount();
const droplets = await this.digitalOcean.getDroplets();
return droplets.length >= (await account).droplet_limit;
}

// Creates a server and returning it when it becomes active.
async createServer(region: digitalocean.Region, name: string): Promise<server.ManagedServer> {
console.time('activeServer');
Expand Down
3 changes: 3 additions & 0 deletions src/server_manager/web_app/testing/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export class FakeDigitalOceanAccount implements digitalocean.Account {
listServers() {
return Promise.resolve(this.servers);
}
async hasReachedLimit(): Promise<boolean> {
return false;
}
listLocations() {
return Promise.resolve([
{
Expand Down

0 comments on commit 1b48be6

Please sign in to comment.