Dennis-Mircea commented on code in PR #1207:
URL: 
https://github.com/apache/flink-kubernetes-operator/pull/1207#discussion_r3959190636


##########
flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/autoscaler/state/ConfigMapStore.java:
##########
@@ -93,9 +102,19 @@ public void removeInfoFromCache(ResourceID resourceID) {
         cache.remove(resourceID);
     }
 
+    private static boolean isNotFound(Exception e) {
+        return e instanceof KubernetesClientException
+                && ((KubernetesClientException) e).getCode() == 
HttpURLConnection.HTTP_NOT_FOUND;
+    }
+
     private ConfigMapView getConfigMap(KubernetesJobAutoScalerContext 
jobContext) {
-        return cache.computeIfAbsent(
-                jobContext.getJobKey(), (id) -> 
getConfigMapFromKubernetes(jobContext));
+        var ownerUid = jobContext.getResource().getMetadata().getUid();
+        return cache.compute(

Review Comment:
   This comment made me think one more time about the whole logic here, so I 
took a step back and reassessed everything one more time.
   
   So, the assessment of the existent code within the operator is the following:
   - The resourceRetriever (which talks directly with the K8s API server) is 
called on the first GET and cached afterwards, and on flush for any updated key 
for a different owner reference.
   - When the actual resource was recreated, it didn’t depend on whether it was 
out of or mid-autoscaler reconciliation cycle, and the flush failed with an 
exception, discarding all the data that was updated within that cycle, and 
triggering a new recreation of the ConfigMap (based on clearing the cache) on 
the next cycle. Also, if the ConfigMap takes more than 1 cycle to be entirely 
deleted, it is continuously writing to a stale ConfigMap that will be deleted 
anyway.
   - This approach, besides the actual exception and error event emitted, is 
also losing at least one autoscaler cycle of computations, which does have 
importance even if we are in the autoscaler metric stabilization window.
   
   The assessment of the previous implementation that I did was the following:
   - The resourceRetriever is called on every GET, and on flush for any updated 
key for a different owner reference. It is not cached because, when building 
the ConfigMapView it will see it as already existent and will use the existent 
ConfigMap data, which references the old owner reference, which causes no cache 
hit while the ConfigMap is not garbage-collected, bringing in place the 
following scenarios:
       - if the previous old ConfigMap is still in place for the whole cycle 
and gets recreated until the next one, we have the same data discarding/loss as 
before + no error + multiple Gets.
       - If the previous old ConfigMap is getting deleted mid-cycle, then we 
are at risk of discarding just a portion of the data (just some key-value 
pairs) while preserving the other, and this brings real inconsistency
       - If the previous old ConfigMap is getting deleted instantly before the 
cycle
   
   So, even with the suggestion that you brought above, this will still cache 
the old ConfigMap data with the new owner reference while the old reference 
ConfigMap still being in place, which can still cause the flush at the end to 
fail with a 404. This will invalidate the cache and will trigger a new 
recreation of the ConfigMap (based on clearing the cache) on the next cycle. 
This will keep the same data discarding logic as before. Still, this approach 
is losing at least one autoscaler cycle of computations, so is not good enough.
   
   Based on the above, I took a step further and I updated the implementation 
with the following logic:
   - On each GET, if the owner reference is different, then get the existing 
ConfigMap (if it wasn’t garbage collected already) and take it over by updating 
the owner reference and clearing the data which is no longer relevant, by doing 
all this computation in memory and by updating the cache, which will no longer 
trigger a miss on the owner reference.
   - At the flush time, try to update the physical ConfigMap if still present 
with the in-memory snapshot, if not, create it from scratch with the data 
collected so far.
   
   To sum up, with the above updated approach, we will no longer be at risk of 
data inconsistency, we will have determinism, and we will not lose any 
autoscaler cycle of computations. I updated the PR content + description to 
reflect this.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to