-
Notifications
You must be signed in to change notification settings - Fork 10
@W-21083961 adding wait support for ODS start stop delete restart #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
b2c277b
958303f
f074db0
18c4bbf
24c29a9
3ab1bf1
8eb29e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| /* | ||
| * Copyright (c) 2025, Salesforce, Inc. | ||
| * SPDX-License-Identifier: Apache-2 | ||
| * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 | ||
| */ | ||
|
|
||
| import {Command} from '@oclif/core'; | ||
|
|
||
| /** | ||
| * Sandbox lifecycle states used for polling. | ||
| * | ||
| * Kept as a simple string union here to avoid depending on internal SDK types. | ||
| */ | ||
| export type SandboxState = 'deleted' | 'failed' | 'started' | 'stopped' | (string & {}); | ||
|
|
||
| interface LoggerLike { | ||
| info(message: string, context?: unknown): void; | ||
| info(context: unknown, message: string): void; | ||
| } | ||
|
|
||
| interface OdsPollResult { | ||
| data?: {data?: {state?: string}}; | ||
| response?: {statusText?: string}; | ||
| } | ||
|
|
||
| interface OdsPollingClient { | ||
| GET: (path: '/sandboxes/{sandboxId}', options: {params: {path: {sandboxId: string}}}) => Promise<OdsPollResult>; | ||
| } | ||
|
|
||
| export interface WaitForSandboxStateOptions { | ||
| sandboxId: string; | ||
| targetState: SandboxState; | ||
| pollIntervalSeconds: number; | ||
| timeoutSeconds: number; | ||
| odsClient: OdsPollingClient; | ||
| logger: LoggerLike; | ||
| onPollError: (message: string) => never; | ||
| onTimeout: (seconds: number) => never; | ||
| onFailure: (state: SandboxState | undefined) => never; | ||
| sleep?: (ms: number) => Promise<void>; | ||
| } | ||
|
|
||
| async function sleep(ms: number): Promise<void> { | ||
| await new Promise((resolve) => { | ||
| setTimeout(resolve, ms); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Shared polling helper for ODS sandbox state transitions. | ||
| * | ||
| * Commands are responsible for user-facing messages and error translations. | ||
| */ | ||
| export async function waitForSandboxStateCommon(options: WaitForSandboxStateOptions): Promise<void> { | ||
| const {sandboxId, targetState, pollIntervalSeconds, timeoutSeconds, odsClient, logger} = options; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I think we should use exceptions over callbacks for failure modes I think we should add a "polling" callback when moving this to the SDK. That way the CLI can report. |
||
| const sleepFn = options.sleep ?? sleep; | ||
|
|
||
| const startTime = Date.now(); | ||
| const pollIntervalMs = pollIntervalSeconds * 1000; | ||
| const timeoutMs = timeoutSeconds * 1000; | ||
|
|
||
| // Initial delay before first poll to give the operation time to start | ||
| await sleepFn(pollIntervalMs); | ||
|
|
||
| while (true) { | ||
| if (timeoutSeconds > 0 && Date.now() - startTime > timeoutMs) { | ||
| options.onTimeout(timeoutSeconds); | ||
| } | ||
|
|
||
| // eslint-disable-next-line no-await-in-loop | ||
| const result = await odsClient.GET('/sandboxes/{sandboxId}', { | ||
| params: { | ||
| path: {sandboxId}, | ||
| }, | ||
| }); | ||
|
|
||
| if (!result.data?.data) { | ||
| options.onPollError(result.response?.statusText || 'Unknown error'); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we move to the SDK I'm not sure this callback is needed. Just use a typed exception and the caller can retry (but I'm not sure we should retry in this type of failure). |
||
| } | ||
|
|
||
| const sandbox = result.data.data; | ||
| const currentState = sandbox.state as SandboxState; | ||
|
|
||
| const elapsed = Math.round((Date.now() - startTime) / 1000); | ||
| const state = currentState || 'unknown'; | ||
| logger.info({sandboxId, elapsed, state}, `[${elapsed}s] State: ${state}`); | ||
|
|
||
| if (currentState === targetState) { | ||
| return; | ||
| } | ||
|
|
||
| if (currentState === 'failed' || currentState === 'deleted') { | ||
| options.onFailure(currentState); | ||
| } | ||
|
|
||
| // eslint-disable-next-line no-await-in-loop | ||
| await sleepFn(pollIntervalMs); | ||
| } | ||
| } | ||
|
|
||
| export default class OdsPolling extends Command { | ||
| static hidden = true; | ||
|
|
||
| async run(): Promise<void> { | ||
| this.error('This is an internal module and not a public command.'); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @charithaT07 I missed this PR.
Can we name this
waitForSandbox?We should probably pull out the entirety of
waitForSandboxfrom the create and just have one.This seems like it should be in the SDK and not the CLI in the
operations/odsmodule as it seems general purpose. In that case it should only trace log (but the CLI can log with the polling callbacks).We should use exceptions for failure modes in the SDK. i.e. I don't think a
onFailurecallback makes sense. But you can use typed exceptions for the different failure types. Same with a TimeoutThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, agreed this should live in the SDK. I moved the sandbox polling logic into salesforce/b2c-tooling-sdk as waitForSandbox() (in operations/ods) and refactored the CLI commands to use it. The SDK now uses typed exceptions for timeout/polling/terminal-state failures and The CLI-local polling implementation is removed.