|
18 | 18 |
|
19 | 19 | package org.apache.flink.kubernetes.operator.utils;
|
20 | 20 |
|
| 21 | +import org.apache.flink.annotation.VisibleForTesting; |
21 | 22 | import org.apache.flink.kubernetes.operator.api.AbstractFlinkResource;
|
22 | 23 | import org.apache.flink.kubernetes.operator.api.FlinkDeployment;
|
23 | 24 | import org.apache.flink.kubernetes.operator.api.lifecycle.ResourceLifecycleState;
|
@@ -127,47 +128,65 @@ private void replaceStatus(CR resource, STATUS prevStatus, KubernetesClient clie
|
127 | 128 | } catch (KubernetesClientException kce) {
|
128 | 129 | // 409 is the error code for conflicts resulting from the locking
|
129 | 130 | if (kce.getCode() == 409) {
|
130 |
| - var currentVersion = resource.getMetadata().getResourceVersion(); |
131 |
| - LOG.debug( |
132 |
| - "Could not apply status update for resource version {}", |
133 |
| - currentVersion); |
134 |
| - |
135 |
| - var latest = client.resource(resource).get(); |
136 |
| - var latestVersion = latest.getMetadata().getResourceVersion(); |
137 |
| - |
138 |
| - if (latestVersion.equals(currentVersion)) { |
139 |
| - // This should not happen as long as the client works consistently |
140 |
| - LOG.error("Unable to fetch latest resource version"); |
141 |
| - throw kce; |
142 |
| - } |
143 |
| - |
144 |
| - if (latest.getStatus().equals(prevStatus)) { |
145 |
| - if (retries++ < 3) { |
146 |
| - LOG.debug( |
147 |
| - "Retrying status update for latest version {}", latestVersion); |
148 |
| - resource.getMetadata().setResourceVersion(latestVersion); |
149 |
| - } else { |
150 |
| - // If we cannot get the latest version in 3 tries we throw the error to |
151 |
| - // retry with delay |
152 |
| - throw kce; |
153 |
| - } |
154 |
| - } else { |
155 |
| - throw new StatusConflictException( |
156 |
| - "Status have been modified externally in version " |
157 |
| - + latestVersion |
158 |
| - + " Previous: " |
159 |
| - + objectMapper.writeValueAsString(prevStatus) |
160 |
| - + " Latest: " |
161 |
| - + objectMapper.writeValueAsString(latest.getStatus())); |
162 |
| - } |
| 131 | + handleLockingError(resource, prevStatus, client, retries, kce); |
| 132 | + ++retries; |
163 | 133 | } else {
|
164 |
| - // We simply throw non conflict errors, to trigger retry with delay |
| 134 | + // We simply throw non-conflict errors, to trigger retry with delay |
165 | 135 | throw kce;
|
166 | 136 | }
|
167 | 137 | }
|
168 | 138 | }
|
169 | 139 | }
|
170 | 140 |
|
| 141 | + @VisibleForTesting |
| 142 | + void handleLockingError( |
| 143 | + CR resource, |
| 144 | + STATUS prevStatus, |
| 145 | + KubernetesClient client, |
| 146 | + int retries, |
| 147 | + KubernetesClientException kce) |
| 148 | + throws JsonProcessingException { |
| 149 | + |
| 150 | + var currentVersion = resource.getMetadata().getResourceVersion(); |
| 151 | + LOG.debug("Could not apply status update for resource version {}", currentVersion); |
| 152 | + |
| 153 | + var latest = client.resource(resource).get(); |
| 154 | + if (latest == null || latest.getMetadata() == null) { |
| 155 | + // This can happen occasionally, we throw the error to retry with delay. |
| 156 | + throw new KubernetesClientException( |
| 157 | + String.format( |
| 158 | + "Failed to retrieve latest %s", |
| 159 | + latest == null ? "resource" : "metadata"), |
| 160 | + kce); |
| 161 | + } |
| 162 | + |
| 163 | + var latestVersion = latest.getMetadata().getResourceVersion(); |
| 164 | + if (currentVersion.equals(latestVersion)) { |
| 165 | + // This should not happen as long as the client works consistently |
| 166 | + LOG.error("Unable to fetch latest resource version"); |
| 167 | + throw kce; |
| 168 | + } |
| 169 | + |
| 170 | + if (latest.getStatus().equals(prevStatus)) { |
| 171 | + if (retries < 3) { |
| 172 | + LOG.debug("Retrying status update for latest version {}", latestVersion); |
| 173 | + resource.getMetadata().setResourceVersion(latestVersion); |
| 174 | + } else { |
| 175 | + // If we cannot get the latest version in 3 tries we throw the error to |
| 176 | + // retry with delay |
| 177 | + throw kce; |
| 178 | + } |
| 179 | + } else { |
| 180 | + throw new StatusConflictException( |
| 181 | + "Status have been modified externally in version " |
| 182 | + + latestVersion |
| 183 | + + " Previous: " |
| 184 | + + objectMapper.writeValueAsString(prevStatus) |
| 185 | + + " Latest: " |
| 186 | + + objectMapper.writeValueAsString(latest.getStatus())); |
| 187 | + } |
| 188 | + } |
| 189 | + |
171 | 190 | /**
|
172 | 191 | * Update the custom resource status based on the in-memory cached to ensure that any status
|
173 | 192 | * updates that we made previously are always visible in the reconciliation loop. This is
|
|
0 commit comments