concurrency: Election.Resign forgets leadership after a failed request
- Dominant language
- Go
- Stars
- 52.3k
- Forks
- 10.5k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 43
Description
### Bug report criteria
- [x] This bug report is not security related, security issues should be disclosed privately via security@etcd.io.
- [x] This is not a support request or question, support requests or questions should be raised in the etcd discussion forums.
- [x] I have read the etcd bug reporting guidelines.
- [x] Existing open issues and the etcd FAQ have been checked and this is not a duplicate.
### What happened?
`concurrency.Election.Resign` clears `leaderKey` and `leaderSession` even when its delete transaction returns an error. If the request never reaches etcd—for example, because the context is already canceled—the leader key remains on the server, but the `Election` forgets it. A later `Resign` then returns `nil` without retrying the delete.
### What did you expect to happen?
`Resign` should retain its local leadership state when the transaction returns an error, allowing the caller to retry. It should clear the state after receiving a successful transaction response.
### How can we reproduce it (as minimally and precisely as possible)?
1. Create a session and successfully campaign in an election.
2. Save `Election.Key()`.
3. Call `Election.Resign` with a context canceled before the call.
4. Observe that `Resign` returns `context.Canceled` and the leader key still exists in etcd.
5. Observe that `Election.Key()` is now empty, so calling `Resign` again is a no-op and cannot remove the key.
A focused integration regression on current `main` fails as follows:
```text
--- FAIL: TestElectionResignCanRetryAfterError
election_resign_test.go:47:
expected: "/resign-retry/60979f79e2255e03"
actual : ""
```
### Anything else we need to know?
The delete is already guarded by a `CreateRevision` comparison, so retaining state and retrying is safe even if the first response was ambiguous: a stale election cannot delete a newer incarnation of the same key.
This is distinct from #21128 and #21165, which concern cleanup after `Election.Campaign` fails. They do not change `Resign`'s behavior when its own transaction fails.
### Etcd version
Current `main` at `6006f405800929b5e7e839e7a821d608a311579f` (the integration server reports `3.8.0-alpha.0`).
```console
$ go version
go version go1.26.5 darwin/arm64
```
### Etcd configuration
The reproduction uses the repository's single-member integration test cluster with its default configuration.
### Etcd debug information
Not applicable; the deterministic integration test reproduces the client-side state transition.
### Relevant log output
```text
rpc error: code = Canceled desc = context canceled
```
Contributor guide
Assessment
This issue has not been assessed yet.