|
42 | 42 | import org.apache.amoro.optimizing.TableOptimizing; |
43 | 43 | import org.apache.amoro.process.ProcessStatus; |
44 | 44 | import org.apache.amoro.resource.ResourceGroup; |
| 45 | +import org.apache.amoro.server.optimizing.OptimizingQueue; |
45 | 46 | import org.apache.amoro.server.optimizing.OptimizingStatus; |
46 | 47 | import org.apache.amoro.server.optimizing.TaskRuntime; |
47 | 48 | import org.apache.amoro.server.persistence.SqlSessionFactoryProvider; |
|
70 | 71 | import org.junit.runner.RunWith; |
71 | 72 | import org.junit.runners.Parameterized; |
72 | 73 |
|
| 74 | +import java.lang.reflect.Method; |
73 | 75 | import java.util.ArrayList; |
74 | 76 | import java.util.List; |
75 | 77 | import java.util.Map; |
@@ -830,4 +832,39 @@ public void run() { |
830 | 832 | } |
831 | 833 | } |
832 | 834 | } |
| 835 | + |
| 836 | + /** |
| 837 | + * Test that stale ack after task reset does not throw exception. Uses reflection to directly |
| 838 | + * reset the task via the queue, simulating the race condition where the task is reset |
| 839 | + * (token=null) but the optimizer is still registered. |
| 840 | + */ |
| 841 | + @Test |
| 842 | + public void testStaleAckAfterTaskReset() throws Exception { |
| 843 | + OptimizingTask task = optimizingService().pollTask(token, THREAD_ID); |
| 844 | + Assertions.assertNotNull(task); |
| 845 | + assertTaskStatus(TaskRuntime.Status.SCHEDULED); |
| 846 | + |
| 847 | + // Reset the task via queue to simulate: task retried by OptimizerKeeper but optimizer still |
| 848 | + // alive |
| 849 | + Method getQueueByToken = |
| 850 | + DefaultOptimizingService.class.getDeclaredMethod("getQueueByToken", String.class); |
| 851 | + getQueueByToken.setAccessible(true); |
| 852 | + OptimizingQueue queue = (OptimizingQueue) getQueueByToken.invoke(optimizingService(), token); |
| 853 | + queue.collectTasks(t -> t.getTaskId().equals(task.getTaskId())).forEach(queue::retryTask); |
| 854 | + |
| 855 | + assertTaskStatus(TaskRuntime.Status.PLANNED); |
| 856 | + |
| 857 | + // Ack with still-valid old token → reaches TaskRuntime.ack() with token==null, gracefully |
| 858 | + // ignored |
| 859 | + optimizingService().ackTask(token, THREAD_ID, task.getTaskId()); |
| 860 | + |
| 861 | + assertTaskStatus(TaskRuntime.Status.PLANNED); |
| 862 | + |
| 863 | + OptimizingTask task2 = optimizingService().pollTask(token, THREAD_ID); |
| 864 | + Assertions.assertEquals(task.getTaskId(), task2.getTaskId()); |
| 865 | + |
| 866 | + optimizingService().ackTask(token, THREAD_ID, task2.getTaskId()); |
| 867 | + optimizingService().completeTask(token, buildOptimizingTaskResult(task2.getTaskId())); |
| 868 | + assertTaskCompleted(optimizingService().listTasks(defaultResourceGroup().getName()).get(0)); |
| 869 | + } |
833 | 870 | } |
0 commit comments