Repository navigation
TEZ-4759: An external AM never re-registers after a ZooKeeper session loss - #543
Conversation
deniskuzZ
commented
Sep 30, 2026
- ZkAMRegistry.add() wrote the AMRecord once, as a bare EPHEMERAL node; a session expiry deletes it and nothing re-creates it, so clients see an empty registry while the AM keeps running
- Hold a Curator PersistentNode per AMRecord: it re-creates the node after a session loss or a delete; remove() closes it
- add() fails when the node is not created within the ZooKeeper connection timeout
- TestZkAMRegistry: after the ZooKeeper server is replaced, the AMRecord node is back
… loss - ZkAMRegistry.add() wrote the AMRecord once, as a bare EPHEMERAL node; a session expiry deletes it and nothing re-creates it, so clients see an empty registry while the AM keeps running - Hold a Curator PersistentNode per AMRecord: it re-creates the node after a session loss or a delete; remove() closes it - add() fails when the node is not created within the ZooKeeper connection timeout - TestZkAMRegistry: after the ZooKeeper server is replaced, the AMRecord node is back
|
🎊 +1 overall
This message was automatically generated. |
abstractdog
left a comment
There was a problem hiding this comment.
nits, otherwise looks good, thanks Denys
| if (node != null) { | ||
| node.close(); // deletes the node | ||
| } | ||
| LOG.info("Deleted AMRecord from zkpath {}", path); |
There was a problem hiding this comment.
this logs "Deleted AMRecord from zkpath" even when nothing was deleted, how about:
if (node == null) {
LOG.debug("AMRecord {} was not registered by this instance, nothing to remove", server);
return;
}
node.close(); // deletes the node
LOG.info("Deleted AMRecord from zkpath {}", pathFor(server));
| byte[] json = AMRegistryUtils.recordToJsonString(server).getBytes(StandardCharsets.UTF_8); | ||
| PersistentNode node = new PersistentNode(client, CreateMode.EPHEMERAL, false, path, json); | ||
| node.start(); | ||
| if (!node.waitForInitialCreate(zkConfig.getConnectionTimeoutMs(), TimeUnit.MILLISECONDS)) { |
There was a problem hiding this comment.
if waitForInitialCreate throws InterruptedException, the node is already started but never closed or put into amNodes, it stays active, so its reconnect listener and NodeDeleted watch keep re-creating the path until close() shuts the Curator client down
what about extra care by:
boolean created;
try {
created = node.waitForInitialCreate(zkConfig.getConnectionTimeoutMs(), TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
node.close();
throw e;
}
if (!created) {
node.close();
throw new IOException("Timed out creating AMRecord at zkpath " + path);
}There was a problem hiding this comment.
Good catch! It's now closed on any failure of the wait
| byte[] json = AMRegistryUtils.recordToJsonString(server).getBytes(StandardCharsets.UTF_8); | ||
| PersistentNode node = new PersistentNode(client, CreateMode.EPHEMERAL, false, path, json); | ||
| node.start(); | ||
| if (!node.waitForInitialCreate(zkConfig.getConnectionTimeoutMs(), TimeUnit.MILLISECONDS)) { |
There was a problem hiding this comment.
add() used to be bounded by the client's retry policy (tez.am.curator.max-retries/backoff-sleep), and now waits a single getConnectionTimeoutMs(). The setting still applies to generateNewId() and to PersistentNode's background creates, so it isn't dead, but someone tuning max-retries might expect registration to wait longer. Scaling the wait by getCuratorMaxRetries() would only make that setting mean something it doesn't, so I'd keep the single timeout and add a comment saying add() waits one connection timeout for the initial create and is not governed by the retry settings.
- remove() logs the delete only when this instance registered the AMRecord - add() closes the node when waiting for the initial create fails, an interrupt included - Comment: the initial create waits one connection timeout, not the Curator retry settings
|
🎊 +1 overall
This message was automatically generated. |