From 012da05287846d94beb0ecdc28d7fbc48c4248ff Mon Sep 17 00:00:00 2001 From: Hannah Date: Mon, 8 Jul 2024 12:01:18 +0100 Subject: [PATCH] Ensure JS client `status_callback` functionality works and improve status messages (#8699) * * bind handle_space_success * ensure status callbacks work correctly * add changeset * test fixes + refactor * tweak * test * Revert "test" This reverts commit db1afc40b4510fd3d2b805b49f334eb4e5ca3e47. --------- Co-authored-by: gradio-pr-bot --- .changeset/fancy-lands-dance.md | 6 ++++ client/js/src/client.ts | 8 ++++- client/js/src/helpers/spaces.ts | 56 ++++++++++++++++++++++++++++++- client/js/src/test/spaces.test.ts | 2 +- client/js/src/types.ts | 9 ++++- 5 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 .changeset/fancy-lands-dance.md diff --git a/.changeset/fancy-lands-dance.md b/.changeset/fancy-lands-dance.md new file mode 100644 index 000000000000..945799376c51 --- /dev/null +++ b/.changeset/fancy-lands-dance.md @@ -0,0 +1,6 @@ +--- +"@gradio/client": patch +"gradio": patch +--- + +fix:Ensure JS client `status_callback` functionality works and improve status messages diff --git a/client/js/src/client.ts b/client/js/src/client.ts index 0ab3a5c876b8..2de70a64fc76 100644 --- a/client/js/src/client.ts +++ b/client/js/src/client.ts @@ -30,7 +30,7 @@ import { get_jwt, parse_and_set_cookies } from "./helpers/init_helpers"; -import { check_space_status } from "./helpers/spaces"; +import { check_and_wake_space, check_space_status } from "./helpers/spaces"; import { open_stream, readable_stream, close_stream } from "./utils/stream"; import { API_INFO_ERROR_MSG, CONFIG_ERROR_MSG } from "./constants"; @@ -141,6 +141,7 @@ export class Client { this.resolve_config = resolve_config.bind(this); this.resolve_cookies = resolve_cookies.bind(this); this.upload = upload.bind(this); + this.handle_space_success = this.handle_space_success.bind(this); } private async init(): Promise { @@ -235,6 +236,11 @@ export class Client { ); const { status_callback } = this.options; + + if (space_id && status_callback) { + await check_and_wake_space(space_id, status_callback); + } + let config: Config | undefined; try { diff --git a/client/js/src/helpers/spaces.ts b/client/js/src/helpers/spaces.ts index 50f66281204a..c290939c52a6 100644 --- a/client/js/src/helpers/spaces.ts +++ b/client/js/src/helpers/spaces.ts @@ -3,6 +3,7 @@ import { SLEEPTIME_URL, SPACE_STATUS_ERROR_MSG } from "../constants"; +import { RE_SPACE_NAME } from "./api_info"; import type { SpaceStatusCallback } from "../types"; export async function check_space_status( @@ -68,7 +69,7 @@ export async function check_space_status( status_callback({ status: "running", load_status: "complete", - message: "", + message: "Space is running.", detail: stage }); break; @@ -80,6 +81,18 @@ export async function check_space_status( detail: stage }); + setTimeout(() => { + check_space_status(id, type, status_callback); + }, 1000); + break; + case "APP_STARTING": + status_callback({ + status: "starting", + load_status: "pending", + message: "Space is starting...", + detail: stage + }); + setTimeout(() => { check_space_status(id, type, status_callback); }, 1000); @@ -96,6 +109,47 @@ export async function check_space_status( } } +export const check_and_wake_space = async ( + space_id: string, + status_callback: SpaceStatusCallback +): Promise => { + let retries = 0; + const max_retries = 12; + const check_interval = 5000; + + return new Promise((resolve) => { + check_space_status( + space_id, + RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", + (status) => { + status_callback(status); + + if (status.status === "running") { + resolve(); + } else if ( + status.status === "error" || + status.status === "paused" || + status.status === "space_error" + ) { + resolve(); + } else if ( + status.status === "sleeping" || + status.status === "building" + ) { + if (retries < max_retries) { + retries++; + setTimeout(() => { + check_and_wake_space(space_id, status_callback).then(resolve); + }, check_interval); + } else { + resolve(); + } + } + } + ); + }); +}; + const RE_DISABLED_DISCUSSION = /^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/; export async function discussions_enabled(space_id: string): Promise { diff --git a/client/js/src/test/spaces.test.ts b/client/js/src/test/spaces.test.ts index 60271ff37a57..77098d8bdff0 100644 --- a/client/js/src/test/spaces.test.ts +++ b/client/js/src/test/spaces.test.ts @@ -84,7 +84,7 @@ describe("check_space_status", () => { expect(status_callback).toHaveBeenCalledWith({ status: "running", load_status: "complete", - message: "", + message: "Space is running.", detail: "RUNNING" }); }); diff --git a/client/js/src/types.ts b/client/js/src/types.ts index d84dd3875b64..63df147090ec 100644 --- a/client/js/src/types.ts +++ b/client/js/src/types.ts @@ -117,12 +117,19 @@ export type PredictReturn = { export type SpaceStatus = SpaceStatusNormal | SpaceStatusError; export interface SpaceStatusNormal { - status: "sleeping" | "running" | "building" | "error" | "stopped"; + status: + | "sleeping" + | "running" + | "building" + | "error" + | "stopped" + | "starting"; detail: | "SLEEPING" | "RUNNING" | "RUNNING_BUILDING" | "BUILDING" + | "APP_STARTING" | "NOT_FOUND"; load_status: "pending" | "error" | "complete" | "generating"; message: string;