chickenchickenlove commented on code in PR #23913:
URL: https://github.com/apache/kafka/pull/23913#discussion_r4369854996


##########
coordinator-common/src/main/java/org/apache/kafka/coordinator/common/runtime/CoordinatorTimerImpl.java:
##########
@@ -166,6 +225,30 @@ public boolean isScheduled(String key) {
     }
 
     public void cancelAll() {
+        states.clear();
+        cancelTasks();
+    }
+
+    /**
+     * Rebuilds the scheduled tasks after the supplied snapshot registry has 
been reverted.
+     * This must be called under the same external synchronization as the 
registry rollback.
+     * It preserves the restored states and their original deadlines.
+     */
+    public void onRollback() {
+        cancelTasks();
+        // A timer implementation may execute an expired task immediately, so 
iterate over
+        // a copy in case that task updates the states while we are 
rescheduling them.
+        new HashMap<>(states).forEach(
+            (key, state) ->
+                scheduleTask(
+                    key,
+                    state,
+                    Math.max(0, state.deadlineMs() - time.hiResClockMs())
+                )
+        );
+    }

Review Comment:
   @dajac @squah-confluent 
   
   I tried implementing an approach where timer changes remain pending until 
the batch is successfully appended to the local log. On success, the changes 
are applied; on failure, they are discarded.
   
   This seems suitable for issues such as KAFKA-21279, where timer changes need 
to be reverted when a write fails. However, applying the same policy to all 
existing `schedule()` and `cancel()` calls revealed that these changes have 
different semantics:
   
   1. Changes that depend on speculative coordinator state should be discarded 
if the corresponding write fails.
   2. Timers scheduled by failure callbacks to restore the previous state must 
survive that recovery.
   3. Changes such as extending a session timeout upon receiving a heartbeat 
require a separate policy decision: should they also be reverted when an 
unrelated write fails?
   
   The current `schedule()` and `cancel()` APIs do not express these 
dependencies. Having the Runtime or TimerImpl infer them from the execution 
path makes the implementation more complex and risks unintentionally changing 
existing behavior.
   
   What do you think about preserving the existing APIs’ immediate scheduling 
and cancellation behavior, while allowing callers to explicitly choose when 
timer changes should depend on the write outcome?
   
   For example, `CoordinatorRuntime` could own both the existing 
`CoordinatorTimerImpl` and a separate `RevertableCoordinatorTimerImpl`, and 
expose both to the coordinator. Callers would use the existing timer for 
changes that should take effect immediately, and explicitly use the revertable 
timer for changes that should be applied or discarded based on the write 
outcome.
   
   If both implementations can operate on timers with the same key, we would 
also need to define how replacement and cancellation interact across them, 
including the order in which changes are applied.
   
   What do you think?



-- 
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