justinmclean opened a new issue, #10217:
URL: https://github.com/apache/gravitino/issues/10217

   ### What would you like to be improved?
   
   CatalogHookDispatcher#createCatalog performs post-create hooks (setOwner, 
future grant) inside a try/catch. On post-hook failure, it attempts rollback 
via dispatcher.dropCatalog(ident, true), then rethrows the original exception. 
If rollback also throws, the rollback exception replaces the original post-hook 
exception. This masks root cause, making debugging and error attribution 
incorrect.
   
   ### How should we improve?
   
   Preserve the original post-hook exception as primary. In the catch, wrap 
dropCatalog in its own try/catch; if rollback fails, attach rollback exception 
as suppressed to the original (e.addSuppressed(rollbackEx)), then rethrow the 
original e. Optionally log rollback failure. This keeps root cause intact while 
still surfacing rollback failure details.
   
   Here's a unit test to help:
   ```
   
   public class TestCatalogHookDispatcher {
   
     @Test
     public void testCreateCatalogRollbackExceptionMasksPostHookException() 
throws Exception {
       GravitinoEnv gravitinoEnv = GravitinoEnv.getInstance();
       Object originalOwnerDispatcher = FieldUtils.readField(gravitinoEnv, 
"ownerDispatcher", true);
       Object originalFutureGrantManager =
           FieldUtils.readField(gravitinoEnv, "futureGrantManager", true);
   
       CatalogDispatcher dispatcher = Mockito.mock(CatalogDispatcher.class);
       Catalog catalog = Mockito.mock(Catalog.class);
       NameIdentifier ident = NameIdentifier.of("metalake", "catalog");
       RuntimeException postHookException = new RuntimeException("post-hook 
failed");
       RuntimeException rollbackException = new RuntimeException("rollback 
failed");
   
       OwnerDispatcher ownerDispatcher = Mockito.mock(OwnerDispatcher.class);
       Mockito.doThrow(postHookException)
           .when(ownerDispatcher)
           .setOwner(Mockito.anyString(), Mockito.any(), Mockito.anyString(), 
Mockito.any());
       Mockito.when(
               dispatcher.createCatalog(
                   Mockito.eq(ident),
                   Mockito.eq(Catalog.Type.RELATIONAL),
                   Mockito.eq("provider"),
                   Mockito.eq("comment"),
                   Mockito.anyMap()))
           .thenReturn(catalog);
       Mockito.doThrow(rollbackException).when(dispatcher).dropCatalog(ident, 
true);
   
       FieldUtils.writeField(gravitinoEnv, "ownerDispatcher", ownerDispatcher, 
true);
       FieldUtils.writeField(gravitinoEnv, "futureGrantManager", null, true);
   
       try {
         CatalogHookDispatcher hookDispatcher = new 
CatalogHookDispatcher(dispatcher);
         RuntimeException thrown =
             assertThrowsExactly(
                 RuntimeException.class,
                 () ->
                     hookDispatcher.createCatalog(
                         ident,
                         Catalog.Type.RELATIONAL,
                         "provider",
                         "comment",
                         Collections.emptyMap()));
         // Expected behavior: preserve original post-hook failure even if 
rollback fails.
         assertSame(postHookException, thrown);
         Mockito.verify(dispatcher).dropCatalog(ident, true);
       } finally {
         FieldUtils.writeField(gravitinoEnv, "ownerDispatcher", 
originalOwnerDispatcher, true);
         FieldUtils.writeField(gravitinoEnv, "futureGrantManager", 
originalFutureGrantManager, true);
       }
     }
   }
   ```


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