Skip to content

Commit bdea926

Browse files
committed
feat: enrich assign_server_event with outcome and configuration
Captures the requested configuration (variant, accelerator, shape, version), whether one or more fallback accelerators were attempted, and the final outcome via a new nested `AssignmentOutcome` enum distinguishing success from `ASSIGNMENT_OUTCOME_ACCELERATOR_UNAVAILABLE`, `ASSIGNMENT_OUTCOME_ALL_ACCELERATORS_UNAVAILABLE`, `ASSIGNMENT_OUTCOME_TOO_MANY_ASSIGNMENTS`, `ASSIGNMENT_OUTCOME_INSUFFICIENT_QUOTA`, `ASSIGNMENT_OUTCOME_DENYLISTED`, and `ASSIGNMENT_OUTCOME_OTHER_FAILURE`. The enum is intentionally distinct from the top-level `Outcome` enum to avoid name collisions in generated code. `hadFallback` is derived in `assignServer` by comparing the returned assignment's accelerator to the requested one (success path), or by checking the thrown `AllAcceleratorsUnavailableError`'s `attempted` array length (failure path).
1 parent a8bbf5e commit bdea926

6 files changed

Lines changed: 412 additions & 61 deletions

File tree

src/jupyter/assignments.ts

Lines changed: 87 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import {
3838
} from '../colab/headers';
3939
import { log } from '../common/logging';
4040
import { telemetry } from '../telemetry';
41-
import { CommandSource } from '../telemetry/api';
41+
import { AssignmentOutcome, CommandSource } from '../telemetry/api';
4242
import { ProxiedJupyterClient } from './client';
4343
import { colabProxyWebSocket } from './colab-proxy-websocket';
4444
import {
@@ -327,60 +327,76 @@ export class AssignmentManager implements Disposable {
327327
this.guardDisposed();
328328
const id = randomUUID();
329329
const { label, variant, accelerator, shape, version } = descriptor;
330-
let assignment: Assignment;
330+
let outcome = AssignmentOutcome.ASSIGNMENT_OUTCOME_UNSPECIFIED;
331+
let hadFallback = false;
331332
try {
332-
if (isColabServerDescriptorWithAccelerator(descriptor)) {
333-
assignment = await this.assignWithFallback(
334-
id,
335-
descriptor,
336-
/* fallbacks= */ undefined,
337-
signal,
338-
);
339-
} else {
340-
({ assignment } = await this.client.assign(
341-
id,
342-
{ variant, accelerator, shape, version },
343-
signal,
344-
));
345-
}
346-
} catch (error) {
347-
log.trace(`Failed assigning server ${id}`, error);
348-
if (error instanceof AllAcceleratorsUnavailableError) {
349-
void this.notifyAllAcceleratorsUnavailable(error);
350-
}
351-
// TODO: Consider listing assignments to check if there are too many
352-
// before the user goes through the assignment flow. This handling logic
353-
// would still be needed for the rare race condition where an assignment
354-
// is made (e.g. in Colab web) during the extension assignment flow.
355-
if (error instanceof TooManyAssignmentsError) {
356-
void this.notifyMaxAssignmentsExceeded();
357-
}
358-
if (error instanceof InsufficientQuotaError) {
359-
void this.notifyInsufficientQuota(error);
360-
}
361-
if (error instanceof DenylistedError) {
362-
this.notifyBanned(error);
333+
let assignment: Assignment;
334+
try {
335+
if (isColabServerDescriptorWithAccelerator(descriptor)) {
336+
assignment = await this.assignWithFallback(
337+
id,
338+
descriptor,
339+
/* fallbacks= */ undefined,
340+
signal,
341+
);
342+
hadFallback = assignment.accelerator !== descriptor.accelerator;
343+
} else {
344+
({ assignment } = await this.client.assign(
345+
id,
346+
{ variant, accelerator, shape, version },
347+
signal,
348+
));
349+
}
350+
} catch (error) {
351+
log.trace(`Failed assigning server ${id}`, error);
352+
outcome = errorToAssignmentOutcome(error);
353+
if (error instanceof AllAcceleratorsUnavailableError) {
354+
hadFallback = error.attempted.length > 1;
355+
void this.notifyAllAcceleratorsUnavailable(error);
356+
}
357+
// TODO: Consider listing assignments to check if there are too many
358+
// before the user goes through the assignment flow. This handling logic
359+
// would still be needed for the rare race condition where an assignment
360+
// is made (e.g. in Colab web) during the extension assignment flow.
361+
if (error instanceof TooManyAssignmentsError) {
362+
void this.notifyMaxAssignmentsExceeded();
363+
}
364+
if (error instanceof InsufficientQuotaError) {
365+
void this.notifyInsufficientQuota(error);
366+
}
367+
if (error instanceof DenylistedError) {
368+
this.notifyBanned(error);
369+
}
370+
throw error;
363371
}
364-
throw error;
372+
const server = this.toAssignedServer(
373+
{
374+
id,
375+
label,
376+
variant: assignment.variant,
377+
accelerator: assignment.accelerator,
378+
},
379+
assignment.endpoint,
380+
assignment.runtimeProxyInfo,
381+
new Date(),
382+
);
383+
await this.storage.store([server]);
384+
this.assignmentChange.fire({
385+
added: [server],
386+
removed: [],
387+
changed: [],
388+
});
389+
outcome = AssignmentOutcome.ASSIGNMENT_OUTCOME_SUCCEEDED;
390+
return server;
391+
} finally {
392+
telemetry.logAssignServer(outcome, {
393+
variant,
394+
accelerator: accelerator ?? '',
395+
shape: shape !== undefined ? Shape[shape] : '',
396+
version: version ?? '',
397+
hadFallback,
398+
});
365399
}
366-
const server = this.toAssignedServer(
367-
{
368-
id,
369-
label,
370-
variant: assignment.variant,
371-
accelerator: assignment.accelerator,
372-
},
373-
assignment.endpoint,
374-
assignment.runtimeProxyInfo,
375-
new Date(),
376-
);
377-
await this.storage.store([server]);
378-
this.assignmentChange.fire({
379-
added: [server],
380-
removed: [],
381-
changed: [],
382-
});
383-
return server;
384400
}
385401

386402
/**
@@ -854,3 +870,22 @@ function isColabServerDescriptorWithAccelerator(
854870
): descriptor is ColabServerDescriptorWithAccelerator {
855871
return !!descriptor.accelerator;
856872
}
873+
874+
function errorToAssignmentOutcome(error: unknown): AssignmentOutcome {
875+
if (error instanceof AllAcceleratorsUnavailableError) {
876+
return AssignmentOutcome.ASSIGNMENT_OUTCOME_ALL_ACCELERATORS_UNAVAILABLE;
877+
}
878+
if (error instanceof AcceleratorUnavailableError) {
879+
return AssignmentOutcome.ASSIGNMENT_OUTCOME_ACCELERATOR_UNAVAILABLE;
880+
}
881+
if (error instanceof TooManyAssignmentsError) {
882+
return AssignmentOutcome.ASSIGNMENT_OUTCOME_TOO_MANY_ASSIGNMENTS;
883+
}
884+
if (error instanceof InsufficientQuotaError) {
885+
return AssignmentOutcome.ASSIGNMENT_OUTCOME_INSUFFICIENT_QUOTA;
886+
}
887+
if (error instanceof DenylistedError) {
888+
return AssignmentOutcome.ASSIGNMENT_OUTCOME_DENYLISTED;
889+
}
890+
return AssignmentOutcome.ASSIGNMENT_OUTCOME_OTHER_FAILURE;
891+
}

0 commit comments

Comments
 (0)