Implement failover and replicaof command - #282
Conversation
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: prateek-kumar-improving <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: prateek-kumar-improving <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: prateek-kumar-improving <prateek.kumar@improving.com>
| $this->assertGTE(1, (int) $info['connected_slaves']); | ||
|
|
||
| // FAILOVER returns true (command accepted, failover is async) | ||
| $result = $client->failover(); |
There was a problem hiding this comment.
Does anything need to get reset with the servers after this test succeeds or fails after an attempted failover so that other following tests aren't affected? i.e. something to run in a tear down-like phase to reset the servers.
|
|
||
| int arg_idx = 0; | ||
|
|
||
| if (abort) { |
There was a problem hiding this comment.
abort doesn't use the timeout parameter?
There was a problem hiding this comment.
If these parameters (host, abort, timeout) have conflicting permutations, it might be worth addressing them the same way it's done in other places.
i.e. @throws ValkeyGlideException If conflicting parameters are specified or connection fails.
Alternatively succeeding and ignoring the conflict might be worth logging. Or perhaps even splitting functions along the abort path.
| zval* z_host = zend_hash_str_find(Z_ARRVAL_P(to_arr), "host", 4); | ||
| zval* z_port = zend_hash_str_find(Z_ARRVAL_P(to_arr), "port", 4); | ||
|
|
||
| if (!z_host || Z_TYPE_P(z_host) != IS_STRING || !z_port) { |
There was a problem hiding this comment.
Similar issue around validation here.
Existing validation patterns look like this
| if (!z_host || Z_TYPE_P(z_host) != IS_STRING || !z_port) { | |
| if (!z_host || Z_TYPE_P(z_host) != IS_STRING || !z_port) { | |
| VALKEY_LOG_ERROR("command_validation", "'to' array must contain string 'host' and 'port'"); | |
| zend_throw_exception(get_valkey_glide_exception_ce(), | |
| "'to' array must contain string 'host' and 'port'", 0); |
I think it makes sense to use that here. Otherwise a malformed $to fails silently with no hint about the problem.
There was a problem hiding this comment.
Might be worth thinking about whether this can be done cohesively around lines 737-740.
| core_args.args[1].data.string_arg.len = 3; | ||
| core_args.arg_count = 2; | ||
| } else { | ||
| /* REPLICAOF host port */ |
There was a problem hiding this comment.
Do we need to do any validation on host here? e.g. should '' be normalized or rejected (and logged iwth explanation) or something else?
| /** | ||
| * Starts a coordinated failover from the connected primary to one of its replicas. | ||
| * | ||
| * @param array|null $to Target replica as ['host' => string, 'port' => int], or null for auto-selection. |
There was a problem hiding this comment.
Nit.
| * @param array|null $to Target replica as ['host' => string, 'port' => int], or null for auto-selection. | |
| * @param array|null $to Target replica as ['host' => string, 'port' => int], or null for auto-selection. |
| /* }}} */ | ||
|
|
||
| /* {{{ proto string ValkeyGlide::bgSave([string mode]) */ | ||
| /* {{{ proto bool ValkeyGlide::bgSave([string mode]) */ |
| // Verify it's currently a master | ||
| $info = $client->info('REPLICATION'); | ||
| $this->assertEquals('master', $info['role']); |
There was a problem hiding this comment.
Can we use waitForRole here?
There was a problem hiding this comment.
(Or assertRole comments suggested in other comment)
| // Verify role changed back to master | ||
| $info = $client->info('REPLICATION'); | ||
| $this->assertEquals('master', $info['role']); |
There was a problem hiding this comment.
Can we use waitForRole here?
There was a problem hiding this comment.
(Or assertRole comments suggested in other comment)
| $client->setOption(ValkeyGlide::OPT_REPLY_LITERAL, true); | ||
| try { | ||
| $result = $client->replicaof('127.0.0.1', 6379); | ||
| $this->assertEquals('OK', $result); | ||
|
|
||
| // Wait for replication to establish | ||
| $client->setOption(ValkeyGlide::OPT_REPLY_LITERAL, false); | ||
| $this->waitForRole($client, 'slave'); | ||
| $client->setOption(ValkeyGlide::OPT_REPLY_LITERAL, true); | ||
|
|
||
| $result = $client->replicaof(); | ||
| $this->assertEquals('OK', $result); | ||
| } finally { | ||
| $client->setOption(ValkeyGlide::OPT_REPLY_LITERAL, false); | ||
| } |
There was a problem hiding this comment.
Didn't we add a helper to simplify the OPT_REPLY_LITERAL cases?
| // Verify role restored to master | ||
| $info = $client->info('REPLICATION'); | ||
| $this->assertEquals('master', $info['role']); | ||
|
|
There was a problem hiding this comment.
Can we use waitForRole here?
There was a problem hiding this comment.
(Or assertRole comments suggested in other comment)
| $this->assertFalse($result); | ||
| } finally { | ||
| $client->setOption(ValkeyGlide::OPT_REPLY_LITERAL, false); | ||
| } |
There was a problem hiding this comment.
Similar comment about using OPT_REPLY_LITERAL helper.
| $info = $client->info('REPLICATION'); | ||
| $this->assertEquals('master', $info['role']); |
There was a problem hiding this comment.
(Or assertRole comments suggested in other comment)
| /** | ||
| * Poll until a server reaches the expected role, or fail after timeout. | ||
| */ | ||
| protected function waitForRole(ValkeyGlide $client, string $expectedRole, int $timeoutMs = 5000): void |
There was a problem hiding this comment.
Do we have a generic waitFor base method that this could use? We have something similar in the other clients. If not, I think it makes sense to add it?
There was a problem hiding this comment.
We should also add an assertRole method. This could be used for cases where we don't need to wait and passed to waitFor for the case where we do?
Summary
Implement REPLICAOF and FAILOVER commands for the standalone ValkeyGlide client.
Issue link
This Pull Request is linked to issue: #236
Features / Behaviour Changes
Implementation
Limitations
Testing
All tests are skipped in cluster mode via overrides in ValkeyGlideClusterTest.
Checklist
Before submitting the PR make sure the following are checked: