| 1 | import * as aiplatform from "@distilled.cloud/gcp/aiplatform_v1"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import { waitForOperation as waitForGcpOperation } from "../Operation.ts"; |
| 4 | |
| 5 | export const resourceNameFromOperation = ( |
| 6 | operation: aiplatform.GoogleLongrunningOperation, |
| 7 | ): string | undefined => { |
| 8 | const response = operation.response; |
| 9 | const responseName = response?.name; |
| 10 | if (typeof responseName === "string" && responseName.length > 0) { |
| 11 | return responseName; |
| 12 | } |
| 13 | const metadata = operation.metadata; |
| 14 | const target = metadata?.target; |
| 15 | if (typeof target === "string" && target.length > 0) { |
| 16 | return target; |
| 17 | } |
| 18 | return undefined; |
| 19 | }; |
| 20 | |
| 21 | /** |
| 22 | * Wait for a Vertex AI long-running operation and return the finished |
| 23 | * operation (so callers can read its `response`). Index deploys and |
| 24 | * feature-store provisioning take up to ~30 minutes. |
| 25 | * |
| 26 | * An operation that failed with ALREADY_EXISTS (6) counts as done (a lost |
| 27 | * create race). With `notFoundOk`, NOT_FOUND (5) — or an operation record |
| 28 | * that is gone — counts as done too (a lost delete race). |
| 29 | */ |
| 30 | export const waitForOperation = ( |
| 31 | operation: aiplatform.GoogleLongrunningOperation, |
| 32 | options?: { notFoundOk?: boolean; alreadyExistsOk?: boolean }, |
| 33 | ) => |
| 34 | Effect.gen(function* () { |
| 35 | const get = (name: string) => |
| 36 | aiplatform.getProjectsLocationsOperations({ name }); |
| 37 | const finished = yield* waitForGcpOperation(operation, get, { |
| 38 | budget: "30 minutes", |
| 39 | }).pipe( |
| 40 | Effect.as(true), |
| 41 | Effect.catchTag("GCP.OperationFailed", (error) => |
| 42 | error.code === 6 || (options?.notFoundOk === true && error.code === 5) |
| 43 | ? Effect.succeed(false) |
| 44 | : Effect.fail(error), |
| 45 | ), |
| 46 | Effect.catchTag("NotFound", (error) => |
| 47 | options?.notFoundOk === true |
| 48 | ? Effect.succeed(false) |
| 49 | : Effect.fail(error), |
| 50 | ), |
| 51 | ); |
| 52 | if (!finished || operation.done === true || !operation.name) { |
| 53 | return operation; |
| 54 | } |
| 55 | return yield* get(operation.name); |
| 56 | }); |