diff --git a/node/npm/glide/index.ts b/node/npm/glide/index.ts index 827d93ee45..66757f0b86 100644 --- a/node/npm/glide/index.ts +++ b/node/npm/glide/index.ts @@ -106,7 +106,8 @@ function initialize() { GlideClientConfiguration, FunctionListOptions, FunctionListResponse, - FunctionStatsResponse, + FunctionStatsSingleResponse, + FunctionStatsFullResponse, SlotIdTypes, SlotKeyTypes, TimeUnit, @@ -200,7 +201,8 @@ function initialize() { GlideClientConfiguration, FunctionListOptions, FunctionListResponse, - FunctionStatsResponse, + FunctionStatsSingleResponse, + FunctionStatsFullResponse, SlotIdTypes, SlotKeyTypes, StreamEntries, diff --git a/node/src/Commands.ts b/node/src/Commands.ts index dee2022c9d..31c085309e 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2220,12 +2220,24 @@ export function createFunctionList( return createCommand(RequestType.FunctionList, args); } -/** Type of the response of `FUNCTION STATS` command. */ -export type FunctionStatsResponse = Record< +/** Response for `FUNCTION STATS` command on a single node. + * The response is a map with 2 keys: + * 1. Information about the current running function/script (or null if none). + * 2. Details about the execution engines. + */ +export type FunctionStatsSingleResponse = Record< string, | null - | Record - | Record> + | Record // Running function/script information + | Record> // Execution engines information +>; + +/** Full response for `FUNCTION STATS` command across multiple nodes. + * It maps node addresses to the per-node response. + */ +export type FunctionStatsFullResponse = Record< + string, // Node address + FunctionStatsSingleResponse >; /** @internal */ diff --git a/node/src/GlideClient.ts b/node/src/GlideClient.ts index c0598c4360..7c69d9eaee 100644 --- a/node/src/GlideClient.ts +++ b/node/src/GlideClient.ts @@ -16,7 +16,7 @@ import { FlushMode, FunctionListOptions, FunctionListResponse, - FunctionStatsResponse, + FunctionStatsFullResponse, InfoOptions, LolwutOptions, SortOptions, @@ -589,51 +589,48 @@ export class GlideClient extends BaseClient { * Returns information about the function that's currently running and information about the * available execution engines. * - * See https://valkey.io/commands/function-stats/ for details. + * FUNCTION STATS runs on all nodes of the cluster, including primary and replicas. + * The response includes a mapping from node address to the command response for that node. * - * since Valkey version 7.0.0. + * See https://valkey.io/commands/function-stats/ for more details. * - * @returns A `Record` with two keys: - * - `"running_script"` with information about the running script. - * - `"engines"` with information about available engines and their stats. + * Since: Valkey version 7.0.0. * - * See example for more details. + * @returns A Record where the key is the node address and the value is a Record with two keys: + * - `"running_script"`: Information about the running script, or `null` if no script is running. + * - `"engines"`: Information about available engines and their stats. * * @example * ```typescript * const response = await client.functionStats(); - * console.log(response); // Output: + * console.log(response); // Example output: * // { - * // "running_script": - * // { - * // "name": "deep_thought", - * // "command": ["fcall", "deep_thought", "0"], - * // "duration_ms": 5008 - * // }, - * // "engines": - * // { - * // "LUA": - * // { - * // "libraries_count": 2, - * // "functions_count": 3 + * // "127.0.0.1:6379": { // Response from the primary node + * // "running_script": { + * // "name": "foo", + * // "command": ["FCALL", "foo", "0", "hello"], + * // "duration_ms": 7758 + * // }, + * // "engines": { + * // "LUA": { + * // "libraries_count": 1, + * // "functions_count": 1 + * // } * // } - * // } - * // } - * // Output if no scripts running: - * // { - * // "running_script": null - * // "engines": - * // { - * // "LUA": - * // { - * // "libraries_count": 2, - * // "functions_count": 3 + * // }, + * // "127.0.0.1:6380": { // Response from a replica node + * // "running_script": null, + * // "engines": { + * // "LUA": { + * // "libraries_count": 1, + * // "functions_count": 1 + * // } * // } * // } * // } * ``` */ - public async functionStats(): Promise { + public async functionStats(): Promise { return this.createWritePromise(createFunctionStats()); } diff --git a/node/src/GlideClusterClient.ts b/node/src/GlideClusterClient.ts index d6a3cbbbf4..c08f11271b 100644 --- a/node/src/GlideClusterClient.ts +++ b/node/src/GlideClusterClient.ts @@ -16,7 +16,6 @@ import { FlushMode, FunctionListOptions, FunctionListResponse, - FunctionStatsResponse, InfoOptions, LolwutOptions, SortClusterOptions, @@ -36,7 +35,6 @@ import { createFlushDB, createFunctionDelete, createFunctionFlush, - createFunctionKill, createFunctionList, createFunctionLoad, createFunctionStats, @@ -912,12 +910,13 @@ export class GlideClusterClient extends BaseClient { * Returns information about the function that's currently running and information about the * available execution engines. * + * * See https://valkey.io/commands/function-stats/ for details. * * since Valkey version 7.0.0. * - * @param route - The client will route the command to the nodes defined by `route`. - * If not defined, the command will be routed to all primary nodes. + * @param route - The command will be routed automatically to all nodes, unless `route` is provided, in which + * case the client will route the command to the nodes defined by `route`. * @returns A `Record` with two keys: * - `"running_script"` with information about the running script. * - `"engines"` with information about available engines and their stats. @@ -960,7 +959,7 @@ export class GlideClusterClient extends BaseClient { */ public async functionStats( route?: Routes, - ): Promise> { + ): Promise> { return this.createWritePromise(createFunctionStats(), { route: toProtobufRoute(route), }); diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 2d90524dd9..af00766f51 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -27,7 +27,7 @@ import { FlushMode, FunctionListOptions, FunctionListResponse, // eslint-disable-line @typescript-eslint/no-unused-vars - FunctionStatsResponse, // eslint-disable-line @typescript-eslint/no-unused-vars + FunctionStatsSingleResponse, // eslint-disable-line @typescript-eslint/no-unused-vars GeoAddOptions, GeoBoxShape, // eslint-disable-line @typescript-eslint/no-unused-vars GeoCircleShape, // eslint-disable-line @typescript-eslint/no-unused-vars @@ -2949,7 +2949,7 @@ export class BaseTransaction> { * * since Valkey version 7.0.0. * - * Command Response - A `Record` of type {@link FunctionStatsResponse} with two keys: + * Command Response - A `Record` of type {@link FunctionStatsSingleResponse} with two keys: * * - `"running_script"` with information about the running script. * - `"engines"` with information about available engines and their stats. diff --git a/node/tests/GlideClient.test.ts b/node/tests/GlideClient.test.ts index 48d1035603..2bbbaa4162 100644 --- a/node/tests/GlideClient.test.ts +++ b/node/tests/GlideClient.test.ts @@ -672,7 +672,10 @@ describe("GlideClient", () => { ).toEqual("one"); let functionStats = await client.functionStats(); - checkFunctionStatsResponse(functionStats, [], 1, 1); + + for (const response of Object.values(functionStats)) { + checkFunctionStatsResponse(response, [], 1, 1); + } let functionList = await client.functionList({ libNamePattern: libName, @@ -733,7 +736,10 @@ describe("GlideClient", () => { ); functionStats = await client.functionStats(); - checkFunctionStatsResponse(functionStats, [], 1, 2); + + for (const response of Object.values(functionStats)) { + checkFunctionStatsResponse(response, [], 1, 2); + } expect( await client.fcall(func2Name, [], ["one", "two"]), @@ -744,7 +750,11 @@ describe("GlideClient", () => { } finally { expect(await client.functionFlush()).toEqual("OK"); const functionStats = await client.functionStats(); - checkFunctionStatsResponse(functionStats, [], 0, 0); + + for (const response of Object.values(functionStats)) { + checkFunctionStatsResponse(response, [], 0, 0); + } + client.close(); } }, diff --git a/node/tests/GlideClusterClient.test.ts b/node/tests/GlideClusterClient.test.ts index 4304a5a988..88fea0e4cf 100644 --- a/node/tests/GlideClusterClient.test.ts +++ b/node/tests/GlideClusterClient.test.ts @@ -28,7 +28,7 @@ import { import { RedisCluster } from "../../utils/TestUtils.js"; import { FlushMode, - FunctionStatsResponse, + FunctionStatsSingleResponse, GeoUnit, SortOrder, } from "../build-ts/src/Commands"; @@ -830,7 +830,7 @@ describe("GlideClusterClient", () => { singleNodeRoute, (value) => checkFunctionStatsResponse( - value as FunctionStatsResponse, + value as FunctionStatsSingleResponse, [], 0, 0, @@ -872,7 +872,7 @@ describe("GlideClusterClient", () => { singleNodeRoute, (value) => checkFunctionStatsResponse( - value as FunctionStatsResponse, + value as FunctionStatsSingleResponse, [], 1, 1, @@ -963,7 +963,7 @@ describe("GlideClusterClient", () => { singleNodeRoute, (value) => checkFunctionStatsResponse( - value as FunctionStatsResponse, + value as FunctionStatsSingleResponse, [], 1, 2, diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index d90283399c..3223119f17 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -19,7 +19,7 @@ import { ClusterTransaction, FlushMode, FunctionListResponse, - FunctionStatsResponse, + FunctionStatsSingleResponse, GeoUnit, GeospatialData, GlideClient, @@ -458,7 +458,7 @@ export function checkFunctionListResponse( * @param functionCount - Expected functions count. */ export function checkFunctionStatsResponse( - response: FunctionStatsResponse, + response: FunctionStatsSingleResponse, runningFunction: string[], libCount: number, functionCount: number, diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index ae5970710d..2a7efb8bf6 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -420,8 +420,8 @@ async def function_stats(self) -> TFunctionStatsFullResponse: } } }, - b"addr2": { - b'running_script': None, # Response from a replica + b"addr2": { # Response from a replica + b'running_script': None, b"engines": { b'LUA': { b'libraries_count': 1,