Read replica reconcile misclassifies existing replicas and keeps rejoined replicas NotReady
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 58/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- kubernetes, mysql, python
- Domain
- databases, infrastructure
Research direction
Start with diagnose_cluster_candidate() in mysqloperator/controller/diagnose.py and trace the reconciliation paths in innodbcluster/cluster_controller.py and shellutils.py. Compare how GR members and read replicas are discovered and how membership status reaches the pod annotation and readiness gate. Done means existing replicas are classified as REJOINABLE and a rejoined ONLINE replica becomes Ready, using the minimal reproduction to verify both cases.
Written by the indexing model from the issue text.
Description
Description
We hit two related bugs with async read replicas managed by the Kubernetes operator:
-
An existing read replica that is already present in InnoDB Cluster metadata can be classified as
JOINABLEinstead ofREJOINABLE, so the operator callsCluster.addReplicaInstance()and gets:
MYSQLSH 51305: Target instance already part of this InnoDB Cluster -
After the replica is manually recovered with
Cluster.rejoinInstance(), the operator still writes pod annotationmysql.oracle.com/membership-infoasstatus=OFFLINEand flips readiness gatemysql.oracle.com/ready=False, even thoughCluster.status()reports the read replicaONLINE.
This leaves the read replica pod Running but not Ready, so Services without publishNotReadyAddresses lose their endpoints.
Operator / server versions
- Helm chart:
mysql-operator2.2.8 - Operator image:
container-registry.oracle.com/mysql/community-operator:9.7.0-2.2.8 - MySQL server image:
container-registry.oracle.com/mysql/community-server:9.6.0 - InnoDBCluster API:
mysql.oracle.com/v2
Cluster shape
- 1 group-member primary
- 1 read replica
router.instances = 0
What we observed
Cluster.status({extended:1})from the primary shows the read replica underdefaultReplicaSet.topology.<primary>.readReplicaswith:- before manual recovery:
status: OFFLINE,instanceErrors: ["WARNING: Read Replica's replication channel is stopped. Use Cluster.rejoinInstance() to restore it."] - after manual recovery:
status: ONLINE
- before manual recovery:
- While the replica was OFFLINE, the operator repeatedly logged:
Setting up '...-rr-0...:3306' as a Read Replica of Cluster '...'
ERROR: The instance '...-rr-0...:3306' is already part of this Cluster. A new Read-Replica must be created on a standalone instance.
MYSQLSH 51305: Target instance already part of this InnoDB Cluster
- After manual
Cluster.rejoinInstance(), replication recovered (Replica_IO_Running=Yes,Replica_SQL_Running=Yes,Seconds_Behind_Source=0) andCluster.status()reported the read replicaONLINE, but the operator still kept the pod readiness gate false until we manually patched pod status.
Suspected root cause
There seem to be two read-replica-specific assumptions in the controller:
-
diagnose_cluster_candidate()checks membership withcluster.status()["defaultReplicaSet"]["topology"].keys().
This only covers GR members. Read replicas live undertopology[*]["readReplicas"], so an existing OFFLINE read replica can be treated as not-a-member and becomeJOINABLEinstead ofREJOINABLE. -
probe_member_status()usesshellutils.query_membership_info(), which only queriesperformance_schema.replication_group_members.
Async read replicas are not GR members, so this returns no row and falls back tostatus="OFFLINE". That value is then written into:- pod annotation
mysql.oracle.com/membership-info - readiness gate
mysql.oracle.com/ready=False
- pod annotation
In trunk, these paths still appear unchanged in:
mysqloperator/controller/diagnose.pymysqloperator/controller/innodbcluster/cluster_controller.pymysqloperator/controller/shellutils.py
Minimal reproduction
- Deploy an
InnoDBClusterwith:instances: 1- one
readReplicasentry withinstances: 1 router.instances: 0
- Stop the async read replica channel on the read replica:
STOP REPLICA FOR CHANNEL 'read_replica_replication'; - Trigger operator reconciliation for the read replica pod (for example, recreate the pod or let the pod create handler run).
- Observe the operator tries
addReplicaInstance()and getsMYSQLSH 51305. - Manually run
Cluster.rejoinInstance('<rr-endpoint>'). - Observe
Cluster.status()shows the replicaONLINE, but the pod annotation/readiness staysOFFLINE/ NotReady.
Expected behavior
- Existing read replicas that are already present in cluster metadata should be classified as
REJOINABLE, notJOINABLE. - After a successful rejoin, the operator should update read replica membership/readiness using a read-replica-aware status source, and the pod should become
Ready.
- Dominant language
- Python
- Stars
- 948
- Forks
- 168
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from mysql/mysql-operator
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
mysql/mysql-operator#50 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
mysql/mysql-operator#56 ·
-
Difficulty 3/5 1-2 days Newbie friendliness 48/100
mysql/mysql-operator#55 · 1 reaction ·
-
The bot is stupid! Open
Difficulty 4/5 3-5 days Newbie friendliness 25/100
mysql/mysql-operator#53 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 52/100
mysql/mysql-operator#52 ·
All issues in mysql/mysql-operator
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
bancolombia/sentinel#23 ·
-
test md OpenCI
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
integration:quickjs org:external priority:backlog topic:code-interpreter topic:middleware type:feature
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
langchain-ai/deepagents#6450 ·
-
bug client
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100