From 52fe7795bf398c64477a0a7fe093ed14963dd8cd Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Tue, 21 Jul 2026 18:43:12 -0700 Subject: [PATCH 1/9] Implement client Pause and Un pause command Signed-off-by: Prateek Kumar --- CHANGELOG.md | 1 + tests/ValkeyGlideClusterTest.php | 56 ++++++++++++++++++++++ tests/ValkeyGlideTest.php | 59 +++++++++++++++++++++++ valkey_glide.stub.php | 27 +++++++++++ valkey_glide_cluster.c | 8 ++++ valkey_glide_cluster.stub.php | 14 ++++++ valkey_glide_commands.c | 80 ++++++++++++++++++++++++++++++++ valkey_glide_commands_common.h | 33 +++++++++++++ valkey_glide_core_common.c | 2 + valkey_z_php_methods.c | 8 ++++ 10 files changed, 288 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e3d202e..6c8e4592 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Changes +* Add `CLIENT PAUSE` and `CLIENT UNPAUSE` commands for standalone and cluster clients ([#274](https://github.com/valkey-io/valkey-glide-php/pull/274)) * Add `BGREWRITEAOF` command for standalone and cluster clients ([#271](https://github.com/valkey-io/valkey-glide-php/pull/271)) * Add `BGSAVE`, `BGSAVE SCHEDULE`, and `BGSAVE CANCEL` commands for standalone and cluster clients ([#236](https://github.com/valkey-io/valkey-glide-php/issues/236)) * Fix pie install from Packagist using PIE pre-packaged-source download method ([#233](https://github.com/valkey-io/valkey-glide-php/pull/233)) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index 1f9758d6..d8679b62 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -644,6 +644,62 @@ public function testBgRewriteAofBatch() } } + public function testClientPause() + { + $result = $this->valkey_glide->clientPause(100); + $this->assertTrue($result); + } + + public function testClientPauseWithMode() + { + // Test with WRITE mode + $result = $this->valkey_glide->clientPause(100, 'WRITE'); + $this->assertTrue($result); + } + + public function testClientUnpause() + { + $result = $this->valkey_glide->clientUnpause(); + $this->assertTrue($result); + } + + public function testClientPauseAndUnpause() + { + // Pause then immediately unpause + $this->assertTrue($this->valkey_glide->clientPause(5000)); + $this->assertTrue($this->valkey_glide->clientUnpause()); + } + + public function testClientPauseWithReplyLiteral() + { + $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, true); + + $result = $this->valkey_glide->clientPause(100); + $this->assertIsString($result); + $this->assertEquals('OK', $result); + + $result = $this->valkey_glide->clientUnpause(); + $this->assertIsString($result); + $this->assertEquals('OK', $result); + + $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, false); + } + + public function testClientPauseBatch() + { + if (!$this->havePipeline()) { + $this->markTestSkipped('Pipeline not supported'); + return; + } + + $this->valkey_glide->pipeline(); + $this->valkey_glide->clientPause(100); + $this->valkey_glide->clientUnpause(); + $result = $this->valkey_glide->exec(); + $this->assertTrue($result[0]); + $this->assertTrue($result[1]); + } + public function testInfo() { $fields = [ diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index 1d39cce5..72d81def 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2707,6 +2707,65 @@ public function testBgRewriteAofBatch() $this->assertTrue($result[0]); } + public function testClientPause() + { + $result = $this->valkey_glide->clientPause(100); + $this->assertTrue($result); + } + + public function testClientPauseWithMode() + { + // Test with WRITE mode - reads still allowed + $result = $this->valkey_glide->clientPause(100, 'WRITE'); + $this->assertTrue($result); + + // Reads should still work during WRITE pause + $this->valkey_glide->set('client_pause_test', 'value'); + } + + public function testClientUnpause() + { + $result = $this->valkey_glide->clientUnpause(); + $this->assertTrue($result); + } + + public function testClientPauseAndUnpause() + { + // Pause then immediately unpause + $this->assertTrue($this->valkey_glide->clientPause(5000)); + $this->assertTrue($this->valkey_glide->clientUnpause()); + } + + public function testClientPauseWithReplyLiteral() + { + $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, true); + + $result = $this->valkey_glide->clientPause(100); + $this->assertIsString($result); + $this->assertEquals('OK', $result); + + $result = $this->valkey_glide->clientUnpause(); + $this->assertIsString($result); + $this->assertEquals('OK', $result); + + $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, false); + } + + public function testClientPauseBatch() + { + if (!$this->havePipeline()) { + $this->markTestSkipped('Pipeline not supported'); + return; + } + + $this->valkey_glide->pipeline(); + $this->valkey_glide->clientPause(100); + $this->valkey_glide->clientUnpause(); + $result = $this->valkey_glide->exec(); + $this->assertTrue($result[0]); + $this->assertTrue($result[1]); + } + /** * Valid BGSAVE response strings (used when OPT_REPLY_LITERAL is enabled). */ diff --git a/valkey_glide.stub.php b/valkey_glide.stub.php index ca262e42..329bcc8b 100644 --- a/valkey_glide.stub.php +++ b/valkey_glide.stub.php @@ -2346,6 +2346,33 @@ public function pfmerge(string $dst, array $srckeys): ValkeyGlide|bool; */ public function ping(?string $message = null): ValkeyGlide|string|bool; + /** + * Suspend all clients for the specified timeout. + * + * All subsequent commands from all clients will be blocked until the timeout expires + * or CLIENT UNPAUSE is called. + * + * @param int $timeout The time in milliseconds to pause clients. + * @param string|null $mode Optional pause mode: "ALL" (default) pauses all commands, + * "WRITE" pauses only write commands (reads still allowed). + * + * @return ValkeyGlide|bool|string Returns true on success, false on failure. + * With OPT_REPLY_LITERAL enabled, returns "OK" instead. + * + * @see https://valkey.io/commands/client-pause + */ + public function clientPause(int $timeout, ?string $mode = null): ValkeyGlide|bool|string; + + /** + * Resume processing commands on all clients that were paused by CLIENT PAUSE. + * + * @return ValkeyGlide|bool|string Returns true on success, false on failure. + * With OPT_REPLY_LITERAL enabled, returns "OK" instead. + * + * @see https://valkey.io/commands/client-unpause + */ + public function clientUnpause(): ValkeyGlide|bool|string; + /** * Enter into pipeline mode. * diff --git a/valkey_glide_cluster.c b/valkey_glide_cluster.c index 58db0f7a..679ce01c 100644 --- a/valkey_glide_cluster.c +++ b/valkey_glide_cluster.c @@ -985,6 +985,14 @@ BGSAVE_METHOD_IMPL(ValkeyGlideCluster) BGREWRITEAOF_METHOD_IMPL(ValkeyGlideCluster) /* }}} */ +/* {{{ proto ValkeyGlideCluster::clientPause(int timeout [, string mode]) */ +CLIENT_PAUSE_METHOD_IMPL(ValkeyGlideCluster) +/* }}} */ + +/* {{{ proto ValkeyGlideCluster::clientUnpause() */ +CLIENT_UNPAUSE_METHOD_IMPL(ValkeyGlideCluster) +/* }}} */ + /* {{{ proto ValkeyGlideCluster::dbsize(string key) * proto ValkeyGlideCluster::dbsize(array host_port) */ DBSIZE_METHOD_IMPL(ValkeyGlideCluster) diff --git a/valkey_glide_cluster.stub.php b/valkey_glide_cluster.stub.php index bc46a603..b8590f59 100644 --- a/valkey_glide_cluster.stub.php +++ b/valkey_glide_cluster.stub.php @@ -966,6 +966,20 @@ public function pfmerge(string $key, array $keys): ValkeyGlideCluster|bool; */ public function ping(mixed $route, ?string $message = null): mixed; + /** + * @see ValkeyGlide::clientPause + * + * Routes to all primary nodes by default. + */ + public function clientPause(int $timeout, ?string $mode = null): ValkeyGlideCluster|bool|string; + + /** + * @see ValkeyGlide::clientUnpause + * + * Routes to all primary nodes by default. + */ + public function clientUnpause(): ValkeyGlideCluster|bool|string; + /** * @see ValkeyGlide::psetex */ diff --git a/valkey_glide_commands.c b/valkey_glide_commands.c index a0115b2c..30dc225f 100644 --- a/valkey_glide_commands.c +++ b/valkey_glide_commands.c @@ -363,6 +363,86 @@ int execute_bgrewriteaof_command(zval* object, int argc, zval* return_value, zen return execute_and_handle_batch(valkey_glide, &core_args, processor, return_value, object); } +/* Execute a CLIENT PAUSE command using the Valkey Glide client - UNIFIED IMPLEMENTATION */ +int execute_client_pause_command(zval* object, int argc, zval* return_value, zend_class_entry* ce) { + valkey_glide_object* valkey_glide; + long timeout; + char* mode = NULL; + size_t mode_len = 0; + + /* Get ValkeyGlide object */ + valkey_glide = VALKEY_GLIDE_PHP_ZVAL_GET_OBJECT(valkey_glide_object, object); + if (!valkey_glide || !valkey_glide->glide_client) { + return 0; + } + + /* Parse parameters: timeout (required), mode (optional) */ + if (zend_parse_method_parameters( + argc, object, "Ol|s!", &object, ce, &timeout, &mode, &mode_len) == FAILURE) { + return 0; + } + + /* Setup core command arguments */ + core_command_args_t core_args = {0}; + core_args.glide_client = valkey_glide->glide_client; + core_args.cmd_type = ClientPause; + core_args.is_cluster = (ce == get_valkey_glide_cluster_ce()); + + /* Add timeout argument */ + core_args.args[0].type = CORE_ARG_TYPE_LONG; + core_args.args[0].data.long_arg.value = timeout; + core_args.arg_count = 1; + + /* Add optional mode argument (ALL or WRITE) */ + if (mode && mode_len > 0) { + core_args.args[1].type = CORE_ARG_TYPE_STRING; + core_args.args[1].data.string_arg.value = mode; + core_args.args[1].data.string_arg.len = mode_len; + core_args.arg_count = 2; + } + + /* Select processor based on OPT_REPLY_LITERAL */ + z_result_processor_t processor = valkey_glide->opt_reply_literal + ? process_core_status_string_result + : process_core_status_bool_result; + + /* Execute using unified core framework */ + return execute_and_handle_batch(valkey_glide, &core_args, processor, return_value, object); +} + +/* Execute a CLIENT UNPAUSE command using the Valkey Glide client - UNIFIED IMPLEMENTATION */ +int execute_client_unpause_command(zval* object, + int argc, + zval* return_value, + zend_class_entry* ce) { + valkey_glide_object* valkey_glide; + + /* Get ValkeyGlide object */ + valkey_glide = VALKEY_GLIDE_PHP_ZVAL_GET_OBJECT(valkey_glide_object, object); + if (!valkey_glide || !valkey_glide->glide_client) { + return 0; + } + + /* No parameters - validate object only */ + if (zend_parse_method_parameters(argc, object, "O", &object, ce) == FAILURE) { + return 0; + } + + /* Setup core command arguments */ + core_command_args_t core_args = {0}; + core_args.glide_client = valkey_glide->glide_client; + core_args.cmd_type = ClientUnpause; + core_args.is_cluster = (ce == get_valkey_glide_cluster_ce()); + + /* Select processor based on OPT_REPLY_LITERAL */ + z_result_processor_t processor = valkey_glide->opt_reply_literal + ? process_core_status_string_result + : process_core_status_bool_result; + + /* Execute using unified core framework */ + return execute_and_handle_batch(valkey_glide, &core_args, processor, return_value, object); +} + /* Execute a TIME command using the Valkey Glide client - UNIFIED IMPLEMENTATION */ int execute_time_command(zval* object, int argc, zval* return_value, zend_class_entry* ce) { valkey_glide_object* valkey_glide; diff --git a/valkey_glide_commands_common.h b/valkey_glide_commands_common.h index b18af154..7c13f9a6 100644 --- a/valkey_glide_commands_common.h +++ b/valkey_glide_commands_common.h @@ -207,6 +207,11 @@ int execute_flushdb_command(zval* object, int argc, zval* return_value, zend_cla int execute_flushall_command(zval* object, int argc, zval* return_value, zend_class_entry* ce); int execute_bgsave_command(zval* object, int argc, zval* return_value, zend_class_entry* ce); int execute_bgrewriteaof_command(zval* object, int argc, zval* return_value, zend_class_entry* ce); +int execute_client_pause_command(zval* object, int argc, zval* return_value, zend_class_entry* ce); +int execute_client_unpause_command(zval* object, + int argc, + zval* return_value, + zend_class_entry* ce); int execute_time_command(zval* object, int argc, zval* return_value, zend_class_entry* ce); int execute_scan_command(zval* object, int argc, zval* return_value, zend_class_entry* ce); int execute_cluster_scan_command(const void* glide_client, @@ -721,6 +726,34 @@ int execute_unlink_command(zval* object, int argc, zval* return_value, zend_clas RETURN_FALSE; \ } +#define CLIENT_PAUSE_METHOD_IMPL(class_name) \ + PHP_METHOD(class_name, clientPause) { \ + if (execute_client_pause_command(getThis(), \ + ZEND_NUM_ARGS(), \ + return_value, \ + strcmp(#class_name, "ValkeyGlideCluster") == 0 \ + ? get_valkey_glide_cluster_ce() \ + : get_valkey_glide_ce())) { \ + return; \ + } \ + zval_dtor(return_value); \ + RETURN_FALSE; \ + } + +#define CLIENT_UNPAUSE_METHOD_IMPL(class_name) \ + PHP_METHOD(class_name, clientUnpause) { \ + if (execute_client_unpause_command(getThis(), \ + ZEND_NUM_ARGS(), \ + return_value, \ + strcmp(#class_name, "ValkeyGlideCluster") == 0 \ + ? get_valkey_glide_cluster_ce() \ + : get_valkey_glide_ce())) { \ + return; \ + } \ + zval_dtor(return_value); \ + RETURN_FALSE; \ + } + #define TIME_METHOD_IMPL(class_name) \ PHP_METHOD(class_name, time) { \ if (execute_time_command(getThis(), \ diff --git a/valkey_glide_core_common.c b/valkey_glide_core_common.c index da2414e3..8678ac7b 100644 --- a/valkey_glide_core_common.c +++ b/valkey_glide_core_common.c @@ -203,6 +203,7 @@ int prepare_core_args(core_command_args_t* args, case Role: case DBSize: case BgRewriteAof: + case ClientUnpause: return prepare_zero_args(args, cmd_args, cmd_args_len); /* Single key operations */ @@ -316,6 +317,7 @@ int prepare_core_args(core_command_args_t* args, case FlushDB: case FlushAll: case BgSave: + case ClientPause: case Select: case SwapDb: return prepare_message_args( diff --git a/valkey_z_php_methods.c b/valkey_z_php_methods.c index b3371574..0117794c 100644 --- a/valkey_z_php_methods.c +++ b/valkey_z_php_methods.c @@ -822,6 +822,14 @@ BGSAVE_METHOD_IMPL(ValkeyGlide) BGREWRITEAOF_METHOD_IMPL(ValkeyGlide) /* }}} */ +/* {{{ proto bool ValkeyGlide::clientPause(int timeout [, string mode]) */ +CLIENT_PAUSE_METHOD_IMPL(ValkeyGlide) +/* }}} */ + +/* {{{ proto bool ValkeyGlide::clientUnpause() */ +CLIENT_UNPAUSE_METHOD_IMPL(ValkeyGlide) +/* }}} */ + /* {{{ proto array ValkeyGlide::time() */ TIME_METHOD_IMPL(ValkeyGlide) /* }}} */ From 81f01e890ac0f4fd9bcc1c7669ea90fccbf79ad4 Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Tue, 21 Jul 2026 21:09:24 -0700 Subject: [PATCH 2/9] Fix tests Signed-off-by: Prateek Kumar --- tests/ValkeyGlideClusterTest.php | 4 ++-- tests/ValkeyGlideTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index d8679b62..c45e9c43 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -665,8 +665,8 @@ public function testClientUnpause() public function testClientPauseAndUnpause() { - // Pause then immediately unpause - $this->assertTrue($this->valkey_glide->clientPause(5000)); + // Use a short pause so it expires before the unpause command times out + $this->assertTrue($this->valkey_glide->clientPause(200)); $this->assertTrue($this->valkey_glide->clientUnpause()); } diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index 72d81def..893e36cd 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2731,8 +2731,8 @@ public function testClientUnpause() public function testClientPauseAndUnpause() { - // Pause then immediately unpause - $this->assertTrue($this->valkey_glide->clientPause(5000)); + // Use a short pause so it expires before the unpause command times out + $this->assertTrue($this->valkey_glide->clientPause(200)); $this->assertTrue($this->valkey_glide->clientUnpause()); } From 6681f03912f5358d0bae2487b435ce4396ab2553 Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Tue, 21 Jul 2026 21:20:57 -0700 Subject: [PATCH 3/9] Fix tests Signed-off-by: Prateek Kumar --- tests/ValkeyGlideClusterTest.php | 14 ++++++++++++-- tests/ValkeyGlideTest.php | 13 ++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index c45e9c43..8e811095 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -652,9 +652,19 @@ public function testClientPause() public function testClientPauseWithMode() { - // Test with WRITE mode - $result = $this->valkey_glide->clientPause(100, 'WRITE'); + // Set a value before pausing + $this->valkey_glide->set('client_pause_test', 'value'); + + // Pause with WRITE mode - only writes are blocked, reads still allowed + $result = $this->valkey_glide->clientPause(2000, 'WRITE'); $this->assertTrue($result); + + // Reads should still work during WRITE pause + $value = $this->valkey_glide->get('client_pause_test'); + $this->assertEquals('value', $value); + + // Unpause to restore normal operation + $this->valkey_glide->clientUnpause(); } public function testClientUnpause() diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index 893e36cd..e0a2e5b0 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2715,12 +2715,19 @@ public function testClientPause() public function testClientPauseWithMode() { - // Test with WRITE mode - reads still allowed - $result = $this->valkey_glide->clientPause(100, 'WRITE'); + // Set a value before pausing + $this->valkey_glide->set('client_pause_test', 'value'); + + // Pause with WRITE mode - only writes are blocked, reads still allowed + $result = $this->valkey_glide->clientPause(2000, 'WRITE'); $this->assertTrue($result); // Reads should still work during WRITE pause - $this->valkey_glide->set('client_pause_test', 'value'); + $value = $this->valkey_glide->get('client_pause_test'); + $this->assertEquals('value', $value); + + // Unpause to restore normal operation + $this->valkey_glide->clientUnpause(); } public function testClientUnpause() From 3afc6e38f0479c93f073339a710532c77f4dd9d5 Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Fri, 24 Jul 2026 10:18:52 -0700 Subject: [PATCH 4/9] Code refactoring based on previous reviews Signed-off-by: Prateek Kumar --- tests/ValkeyGlideClusterTest.php | 18 ++++++++---------- tests/ValkeyGlideTest.php | 18 ++++++++---------- valkey_glide.stub.php | 6 ++++-- valkey_glide_cluster.stub.php | 4 ---- valkey_glide_commands.c | 3 --- valkey_glide_commands_common.h | 6 ++++++ 6 files changed, 26 insertions(+), 29 deletions(-) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index 05ab6213..f9d078b9 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -675,17 +675,15 @@ public function testClientPauseAndUnpause() public function testClientPauseWithReplyLiteral() { - $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, true); - - $result = $this->valkey_glide->clientPause(100); - $this->assertIsString($result); - $this->assertEquals('OK', $result); - - $result = $this->valkey_glide->clientUnpause(); - $this->assertIsString($result); - $this->assertEquals('OK', $result); + $this->withOptReplyLiteralEnabled(function () { + $result = $this->valkey_glide->clientPause(100); + $this->assertIsString($result); + $this->assertEquals('OK', $result); - $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, false); + $result = $this->valkey_glide->clientUnpause(); + $this->assertIsString($result); + $this->assertEquals('OK', $result); + }); } public function testClientPauseBatch() diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index 28ad27cf..e4910812 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2759,17 +2759,15 @@ public function testClientPauseAndUnpause() public function testClientPauseWithReplyLiteral() { - $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, true); - - $result = $this->valkey_glide->clientPause(100); - $this->assertIsString($result); - $this->assertEquals('OK', $result); - - $result = $this->valkey_glide->clientUnpause(); - $this->assertIsString($result); - $this->assertEquals('OK', $result); + $this->withOptReplyLiteralEnabled(function () { + $result = $this->valkey_glide->clientPause(100); + $this->assertIsString($result); + $this->assertEquals('OK', $result); - $this->valkey_glide->setOption(ValkeyGlide::OPT_REPLY_LITERAL, false); + $result = $this->valkey_glide->clientUnpause(); + $this->assertIsString($result); + $this->assertEquals('OK', $result); + }); } public function testClientPauseBatch() diff --git a/valkey_glide.stub.php b/valkey_glide.stub.php index c4e366a3..fc6e64ba 100644 --- a/valkey_glide.stub.php +++ b/valkey_glide.stub.php @@ -2371,7 +2371,8 @@ public function ping(?string $message = null): ValkeyGlide|string|bool; * "WRITE" pauses only write commands (reads still allowed). * * @return ValkeyGlide|bool|string Returns true on success, false on failure. - * With OPT_REPLY_LITERAL enabled, returns "OK" instead. + * With OPT_REPLY_LITERAL enabled, returns "OK" on success, + * false on failure. * * @see https://valkey.io/commands/client-pause */ @@ -2381,7 +2382,8 @@ public function clientPause(int $timeout, ?string $mode = null): ValkeyGlide|boo * Resume processing commands on all clients that were paused by CLIENT PAUSE. * * @return ValkeyGlide|bool|string Returns true on success, false on failure. - * With OPT_REPLY_LITERAL enabled, returns "OK" instead. + * With OPT_REPLY_LITERAL enabled, returns "OK" on success, + * false on failure. * * @see https://valkey.io/commands/client-unpause */ diff --git a/valkey_glide_cluster.stub.php b/valkey_glide_cluster.stub.php index c64a6e15..f487b873 100644 --- a/valkey_glide_cluster.stub.php +++ b/valkey_glide_cluster.stub.php @@ -973,15 +973,11 @@ public function ping(mixed $route, ?string $message = null): mixed; /** * @see ValkeyGlide::clientPause - * - * Routes to all primary nodes by default. */ public function clientPause(int $timeout, ?string $mode = null): ValkeyGlideCluster|bool|string; /** * @see ValkeyGlide::clientUnpause - * - * Routes to all primary nodes by default. */ public function clientUnpause(): ValkeyGlideCluster|bool|string; diff --git a/valkey_glide_commands.c b/valkey_glide_commands.c index 20f6ac4a..c98b545e 100644 --- a/valkey_glide_commands.c +++ b/valkey_glide_commands.c @@ -475,7 +475,6 @@ int execute_client_pause_command(zval* object, int argc, zval* return_value, zen ? process_core_status_string_result : process_core_status_bool_result; - /* Execute using unified core framework */ return execute_and_handle_batch(valkey_glide, &core_args, processor, return_value, object); } @@ -508,7 +507,6 @@ int execute_client_unpause_command(zval* object, ? process_core_status_string_result : process_core_status_bool_result; - /* Execute using unified core framework */ return execute_and_handle_batch(valkey_glide, &core_args, processor, return_value, object); } @@ -611,7 +609,6 @@ int execute_unwatch_command(zval* object, int argc, zval* return_value, zend_cla return 0; } - /* Execute using core framework */ core_command_args_t args = {0}; args.glide_client = valkey_glide->glide_client; args.cmd_type = UnWatch; diff --git a/valkey_glide_commands_common.h b/valkey_glide_commands_common.h index b5c563c9..1cfbbf12 100644 --- a/valkey_glide_commands_common.h +++ b/valkey_glide_commands_common.h @@ -494,6 +494,12 @@ int execute_unlink_command(zval* object, int argc, zval* return_value, zend_clas #define RESET_METHOD_IMPL(class_name) STANDARD_METHOD_IMPL(class_name, reset, execute_reset_command) +#define CLIENT_PAUSE_METHOD_IMPL(class_name) \ + STANDARD_METHOD_IMPL(class_name, clientPause, execute_client_pause_command) + +#define CLIENT_UNPAUSE_METHOD_IMPL(class_name) \ + STANDARD_METHOD_IMPL(class_name, clientUnpause, execute_client_unpause_command) + #define TIME_METHOD_IMPL(class_name) STANDARD_METHOD_IMPL(class_name, time, execute_time_command) #define SCAN_METHOD_IMPL(class_name) STANDARD_METHOD_IMPL(class_name, scan, execute_scan_command) From 0ab48bf93b9c51c276f957336b62bfb3b2e1f299 Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Fri, 24 Jul 2026 10:31:36 -0700 Subject: [PATCH 5/9] Update tests Signed-off-by: Prateek Kumar --- tests/ValkeyGlideClusterTest.php | 57 ++++++++++++++++++++++++-------- tests/ValkeyGlideTest.php | 55 +++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index f9d078b9..234db53c 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -639,38 +639,69 @@ public function testBgRewriteAofBatch() public function testClientPause() { - $result = $this->valkey_glide->clientPause(100); + $key = '{client_pause_all}_' . uniqid(); + $this->valkey_glide->set($key, 'before'); + + $pauseMs = 2000; + $result = $this->valkey_glide->clientPause($pauseMs); $this->assertTrue($result); + + // Verify that reads are blocked until the pause expires + $start = microtime(true); + $value = $this->valkey_glide->get($key); + $elapsed = (microtime(true) - $start) * 1000; + + $this->assertEquals('before', $value); + $this->assertGTE($pauseMs * 0.8, $elapsed); + + $this->valkey_glide->del($key); } public function testClientPauseWithMode() { - // Set a value before pausing - $this->valkey_glide->set('client_pause_test', 'value'); + $key = '{client_pause_write}_' . uniqid(); + $this->valkey_glide->set($key, 'value'); // Pause with WRITE mode - only writes are blocked, reads still allowed - $result = $this->valkey_glide->clientPause(2000, 'WRITE'); + $pauseMs = 60000; + $result = $this->valkey_glide->clientPause($pauseMs, 'WRITE'); $this->assertTrue($result); - // Reads should still work during WRITE pause - $value = $this->valkey_glide->get('client_pause_test'); + // Reads should still work quickly during WRITE pause + $start = microtime(true); + $value = $this->valkey_glide->get($key); + $elapsed = (microtime(true) - $start) * 1000; + $this->assertEquals('value', $value); + $this->assertLT($pauseMs, $elapsed); // Unpause to restore normal operation $this->valkey_glide->clientUnpause(); + $this->valkey_glide->del($key); } public function testClientUnpause() { + $key = '{client_unpause}_' . uniqid(); + $this->valkey_glide->set($key, 'before'); + + // Pause writes for a long time + $pauseMs = 60000; + $this->valkey_glide->clientPause($pauseMs, 'WRITE'); + + // Unpause should unblock immediately $result = $this->valkey_glide->clientUnpause(); $this->assertTrue($result); - } - public function testClientPauseAndUnpause() - { - // Use a short pause so it expires before the unpause command times out - $this->assertTrue($this->valkey_glide->clientPause(200)); - $this->assertTrue($this->valkey_glide->clientUnpause()); + // Verify writes work quickly after unpause + $start = microtime(true); + $this->valkey_glide->set($key, 'after'); + $elapsed = (microtime(true) - $start) * 1000; + + $this->assertLT($pauseMs, $elapsed); + $this->assertEquals('after', $this->valkey_glide->get($key)); + + $this->valkey_glide->del($key); } public function testClientPauseWithReplyLiteral() @@ -701,7 +732,7 @@ public function testClientPauseBatch() $this->assertTrue($result[1]); } - public function testReset() + public function testReset() { $key = '{reset_test}_' . uniqid(); diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index e4910812..3f167a11 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2723,38 +2723,69 @@ public function testBgRewriteAofBatch() public function testClientPause() { - $result = $this->valkey_glide->clientPause(100); + $key = 'client_pause_all_' . $this->createRandomString(); + $this->valkey_glide->set($key, 'before'); + + $pauseMs = 2000; + $result = $this->valkey_glide->clientPause($pauseMs); $this->assertTrue($result); + + // Verify that reads are blocked until the pause expires + $start = microtime(true); + $value = $this->valkey_glide->get($key); + $elapsed = (microtime(true) - $start) * 1000; + + $this->assertEquals('before', $value); + $this->assertGTE($pauseMs * 0.8, $elapsed); + + $this->valkey_glide->del($key); } public function testClientPauseWithMode() { - // Set a value before pausing - $this->valkey_glide->set('client_pause_test', 'value'); + $key = 'client_pause_write_' . $this->createRandomString(); + $this->valkey_glide->set($key, 'value'); // Pause with WRITE mode - only writes are blocked, reads still allowed - $result = $this->valkey_glide->clientPause(2000, 'WRITE'); + $pauseMs = 60000; + $result = $this->valkey_glide->clientPause($pauseMs, 'WRITE'); $this->assertTrue($result); - // Reads should still work during WRITE pause - $value = $this->valkey_glide->get('client_pause_test'); + // Reads should still work quickly during WRITE pause + $start = microtime(true); + $value = $this->valkey_glide->get($key); + $elapsed = (microtime(true) - $start) * 1000; + $this->assertEquals('value', $value); + $this->assertLT($pauseMs, $elapsed); // Unpause to restore normal operation $this->valkey_glide->clientUnpause(); + $this->valkey_glide->del($key); } public function testClientUnpause() { + $key = 'client_unpause_' . $this->createRandomString(); + $this->valkey_glide->set($key, 'before'); + + // Pause writes for a long time + $pauseMs = 60000; + $this->valkey_glide->clientPause($pauseMs, 'WRITE'); + + // Unpause should unblock immediately $result = $this->valkey_glide->clientUnpause(); $this->assertTrue($result); - } - public function testClientPauseAndUnpause() - { - // Use a short pause so it expires before the unpause command times out - $this->assertTrue($this->valkey_glide->clientPause(200)); - $this->assertTrue($this->valkey_glide->clientUnpause()); + // Verify writes work quickly after unpause + $start = microtime(true); + $this->valkey_glide->set($key, 'after'); + $elapsed = (microtime(true) - $start) * 1000; + + $this->assertLT($pauseMs, $elapsed); + $this->assertEquals('after', $this->valkey_glide->get($key)); + + $this->valkey_glide->del($key); } public function testClientPauseWithReplyLiteral() From 5defcb00771f653f758f9aca1c7bb2b61cee7f4a Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Fri, 24 Jul 2026 10:38:03 -0700 Subject: [PATCH 6/9] Fix lint error Signed-off-by: Prateek Kumar --- valkey_glide_cluster.c | 2 +- valkey_z_php_methods.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/valkey_glide_cluster.c b/valkey_glide_cluster.c index 93b5dc66..37856d20 100644 --- a/valkey_glide_cluster.c +++ b/valkey_glide_cluster.c @@ -991,7 +991,7 @@ CLIENT_PAUSE_METHOD_IMPL(ValkeyGlideCluster) /* {{{ proto ValkeyGlideCluster::clientUnpause() */ CLIENT_UNPAUSE_METHOD_IMPL(ValkeyGlideCluster) -/* }}} */ +/* }}} */ /* {{{ proto ValkeyGlideCluster::reset() */ RESET_METHOD_IMPL(ValkeyGlideCluster) diff --git a/valkey_z_php_methods.c b/valkey_z_php_methods.c index d80d668f..3b50da5f 100644 --- a/valkey_z_php_methods.c +++ b/valkey_z_php_methods.c @@ -828,7 +828,7 @@ CLIENT_PAUSE_METHOD_IMPL(ValkeyGlide) /* {{{ proto bool ValkeyGlide::clientUnpause() */ CLIENT_UNPAUSE_METHOD_IMPL(ValkeyGlide) -/* }}} */ +/* }}} */ /* {{{ proto bool ValkeyGlide::reset() */ RESET_METHOD_IMPL(ValkeyGlide) From e9dfc431a0bc88866be1d53f35bd69211e8d2791 Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Fri, 24 Jul 2026 10:44:03 -0700 Subject: [PATCH 7/9] Fix lint error Signed-off-by: Prateek Kumar --- tests/ValkeyGlideClusterTest.php | 2 +- tests/ValkeyGlideTest.php | 2 +- valkey_glide_cluster.stub.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index 234db53c..fbe76dfb 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -731,7 +731,7 @@ public function testClientPauseBatch() $this->assertTrue($result[0]); $this->assertTrue($result[1]); } - + public function testReset() { $key = '{reset_test}_' . uniqid(); diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index 3f167a11..bd7f39c8 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2815,7 +2815,7 @@ public function testClientPauseBatch() $this->assertTrue($result[0]); $this->assertTrue($result[1]); } - + public function testReset() { $key = '{reset_test}_' . $this->createRandomString(); diff --git a/valkey_glide_cluster.stub.php b/valkey_glide_cluster.stub.php index f487b873..4068048b 100644 --- a/valkey_glide_cluster.stub.php +++ b/valkey_glide_cluster.stub.php @@ -981,7 +981,7 @@ public function clientPause(int $timeout, ?string $mode = null): ValkeyGlideClus */ public function clientUnpause(): ValkeyGlideCluster|bool|string; - /** + /** * @see ValkeyGlide::reset */ public function reset(): ValkeyGlideCluster|bool|string; From 4ba262899c9acbd00fcf8bb9dece889258d5d94e Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Tue, 28 Jul 2026 10:12:14 -0700 Subject: [PATCH 8/9] Fix tests Signed-off-by: Prateek Kumar --- tests/ValkeyGlideClusterTest.php | 10 ++++++++++ tests/ValkeyGlideTest.php | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index fbe76dfb..286afae1 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -659,6 +659,11 @@ public function testClientPause() public function testClientPauseWithMode() { + if (!$this->minVersionCheck('6.2.0')) { + $this->markTestSkipped('CLIENT PAUSE WRITE requires 6.2.0+'); + return; + } + $key = '{client_pause_write}_' . uniqid(); $this->valkey_glide->set($key, 'value'); @@ -682,6 +687,11 @@ public function testClientPauseWithMode() public function testClientUnpause() { + if (!$this->minVersionCheck('6.2.0')) { + $this->markTestSkipped('CLIENT PAUSE WRITE requires 6.2.0+'); + return; + } + $key = '{client_unpause}_' . uniqid(); $this->valkey_glide->set($key, 'before'); diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index bd7f39c8..fa322b58 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2743,6 +2743,11 @@ public function testClientPause() public function testClientPauseWithMode() { + if (!$this->minVersionCheck('6.2.0')) { + $this->markTestSkipped('CLIENT PAUSE WRITE requires 6.2.0+'); + return; + } + $key = 'client_pause_write_' . $this->createRandomString(); $this->valkey_glide->set($key, 'value'); @@ -2766,6 +2771,11 @@ public function testClientPauseWithMode() public function testClientUnpause() { + if (!$this->minVersionCheck('6.2.0')) { + $this->markTestSkipped('CLIENT PAUSE WRITE requires 6.2.0+'); + return; + } + $key = 'client_unpause_' . $this->createRandomString(); $this->valkey_glide->set($key, 'before'); From 5e8718a30cd153f89ad16ae6bb8eb3ad4a6d4ec5 Mon Sep 17 00:00:00 2001 From: Prateek Kumar Date: Tue, 28 Jul 2026 10:27:04 -0700 Subject: [PATCH 9/9] Add finally to tests Signed-off-by: Prateek Kumar --- tests/ValkeyGlideClusterTest.php | 20 +++++++++++--------- tests/ValkeyGlideTest.php | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tests/ValkeyGlideClusterTest.php b/tests/ValkeyGlideClusterTest.php index 286afae1..6d9d3e7c 100644 --- a/tests/ValkeyGlideClusterTest.php +++ b/tests/ValkeyGlideClusterTest.php @@ -672,16 +672,18 @@ public function testClientPauseWithMode() $result = $this->valkey_glide->clientPause($pauseMs, 'WRITE'); $this->assertTrue($result); - // Reads should still work quickly during WRITE pause - $start = microtime(true); - $value = $this->valkey_glide->get($key); - $elapsed = (microtime(true) - $start) * 1000; - - $this->assertEquals('value', $value); - $this->assertLT($pauseMs, $elapsed); + try { + // Reads should still work quickly during WRITE pause + $start = microtime(true); + $value = $this->valkey_glide->get($key); + $elapsed = (microtime(true) - $start) * 1000; + + $this->assertEquals('value', $value); + $this->assertLT($pauseMs, $elapsed); + } finally { + $this->valkey_glide->clientUnpause(); + } - // Unpause to restore normal operation - $this->valkey_glide->clientUnpause(); $this->valkey_glide->del($key); } diff --git a/tests/ValkeyGlideTest.php b/tests/ValkeyGlideTest.php index fa322b58..96b4f016 100644 --- a/tests/ValkeyGlideTest.php +++ b/tests/ValkeyGlideTest.php @@ -2756,16 +2756,18 @@ public function testClientPauseWithMode() $result = $this->valkey_glide->clientPause($pauseMs, 'WRITE'); $this->assertTrue($result); - // Reads should still work quickly during WRITE pause - $start = microtime(true); - $value = $this->valkey_glide->get($key); - $elapsed = (microtime(true) - $start) * 1000; + try { + // Reads should still work quickly during WRITE pause + $start = microtime(true); + $value = $this->valkey_glide->get($key); + $elapsed = (microtime(true) - $start) * 1000; - $this->assertEquals('value', $value); - $this->assertLT($pauseMs, $elapsed); + $this->assertEquals('value', $value); + $this->assertLT($pauseMs, $elapsed); + } finally { + $this->valkey_glide->clientUnpause(); + } - // Unpause to restore normal operation - $this->valkey_glide->clientUnpause(); $this->valkey_glide->del($key); }