diff --git a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/support/DirectoryWatchSupport.java b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/support/DirectoryWatchSupport.java index 631129b1..f6e13935 100644 --- a/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/support/DirectoryWatchSupport.java +++ b/Partner-Framework/src/main/java/work/slhaf/partner/framework/agent/support/DirectoryWatchSupport.java @@ -157,7 +157,11 @@ public class DirectoryWatchSupport implements Closeable { if (handler == null) { continue; } - handler.handle(thisDir, resolvedContext); + try { + handler.handle(thisDir, resolvedContext); + } catch (Exception e) { + log.error("监听事件处理失败: dir={}, kind={}, context={}", thisDir, kind.name(), resolvedContext, e); + } } } catch (InterruptedException e) { log.info("监听线程被中断,准备退出..."); diff --git a/Partner-Framework/src/test/java/work/slhaf/partner/framework/common/support/DirectoryWatchSupportTest.java b/Partner-Framework/src/test/java/work/slhaf/partner/framework/common/support/DirectoryWatchSupportTest.java index a12e5ded..ce73b417 100644 --- a/Partner-Framework/src/test/java/work/slhaf/partner/framework/common/support/DirectoryWatchSupportTest.java +++ b/Partner-Framework/src/test/java/work/slhaf/partner/framework/common/support/DirectoryWatchSupportTest.java @@ -11,8 +11,11 @@ import java.nio.file.Path; import java.util.Comparator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BooleanSupplier; class DirectoryWatchSupportTest { @@ -115,6 +118,41 @@ class DirectoryWatchSupportTest { } } + @Test + void testHandlerExceptionDoesNotStopWatching(@TempDir Path tempDir) throws Exception { + AtomicBoolean shouldThrow = new AtomicBoolean(true); + CountDownLatch goodEventLatch = new CountDownLatch(1); + + try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); + DirectoryWatchSupport watchSupport = new DirectoryWatchSupport( + new DirectoryWatchSupport.Context(tempDir), + executor, + 0, + null + )) { + List events = new CopyOnWriteArrayList<>(); + watchSupport.onCreate((thisDir, context) -> { + if (context == null || Files.isDirectory(context)) { + return; + } + String relative = tempDir.relativize(context).toString().replace('\\', '/'); + if (shouldThrow.getAndSet(false)) { + throw new IllegalStateException("boom"); + } + events.add(relative); + goodEventLatch.countDown(); + }); + + watchSupport.start(); + + Files.writeString(tempDir.resolve("first.txt"), "first"); + Files.writeString(tempDir.resolve("second.txt"), "second"); + + Assertions.assertTrue(goodEventLatch.await(2, TimeUnit.SECONDS)); + Assertions.assertEquals(List.of("second.txt"), events); + } + } + private WatchHarness createWatchSupport(Path root, ExecutorService executor, int watchDepth) throws IOException { DirectoryWatchSupport watchSupport = new DirectoryWatchSupport(new DirectoryWatchSupport.Context(root), executor, watchDepth, null); List events = new CopyOnWriteArrayList<>();