4

I'm using Java's WatchService API within my Spring Boot application to monitor a directory, and perform some actions on created files. This process is executed asynchronously: it starts automatically right after the application is ready and monitors the directory in the background until the application is stopped.

This is the configuration class:

@Configuration
public class DirectoryWatcherConfig {

    @Value("${path}")
    private String path;

    @Bean
    public WatchService watchService() throws IOException {
        WatchService watchService = FileSystems.getDefault().newWatchService();
        Path directoryPath = Paths.get(path);
        directoryPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
        return watchService;
    }

}

And this is the monitoring service:

@Service
@RequiredArgsConstructor
public class DirectoryWatcherService {

    private final WatchService watchService;

    @Async
    @EventListener(ApplicationReadyEvent.class)
    public void startWatching() throws InterruptedException {
        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                // actions on created files
            }

            key.reset();
        }
    }

}

This code is working as expected, with the following exception, which I'd like to fix:

  • Any failure during the execution makes the monitoring to stop (obviously), and I don't know how to restart the monitoring after such events occur

2 Answers 2

2
+25

You should change the loop with and add a try/Catch, in the catch restarting the service. As you commented you need to keep in even if is interrupted , so you will need the use of ExecutorService. Declare the Executor out of the method

@Autowired
private ExecutorService executor;

and inside the method something similar to my last answer but using the executor

Runnable task = () -> {
        while (true) {
            try {
                WatchKey key = watchService.take();
                if (key != null) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        // Perform actions on created files here
                    }
                    key.reset();
                }
            } catch (Exception e) {
                // Wait for some time before starting the thread again
                Thread.sleep(5000);
            }
        }
    };
    //submit the task to the executor
    executor.submit(task);
1
  • The problem is not that the watchService is closed, but any exception occurred during execution of this method makes the thread to stop (note that this process is executed asynchronously). What I need is to restart this process asyncrhonously every time its execution is interrupted
    – thmasker
    Commented Jan 23, 2023 at 10:36
0

Actually the solution was quite simple. Wrapping the desired actions with try/catch (catching desired exceptions) in DirectoryWatcherService like this allows the thread to continue monitoring directories:

@Service
@RequiredArgsConstructor
public class DirectoryWatcherService {

    private final WatchService watchService;

    @Async
    @EventListener(ApplicationReadyEvent.class)
    public void startWatching() throws InterruptedException {
        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                try {
                    // actions on created files
                } catch (RuntimeException ex) {
                    // log exception or whatever you choose, as long as execution continues
                }
            }

            key.reset();
        }
    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.