I'm trying to watching file created event on Directory using FileSystemWatcher of Spring boot devtools filewatch package It's work fine when catch created event when file be written. But I facing a problem when write file with high frequency. FileSystemWatcher will waiting until all files be written then fire created event for each file.
So, I want FileSystemWatcher will fire created event when each file written, not wait to all file be written then fire events. How can I do that. Here is my code:
@Configuration
public class FileWatchingConfiguration {
private Logger logger = LoggerFactory.getLogger(FileWatchingConfiguration.class);
@Value("${application.scope}")
private String appScope;
@Autowired
DataFileChangeListener dataFileChangeListener;
@Bean
public FileSystemWatcher destDataWatcher(){
String folderPath = appScope.equalsIgnoreCase("external") ? Utils.getSyncFolderPath(Constants.DIR_TYPE.EXT_DEST_DATA) : Utils.getSyncFolderPath(Constants.DIR_TYPE.INT_DEST_DATA);
logger.info("Data Watcher folder path watching change " + folderPath );
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(true, Duration.ofMillis(1000L), Duration.ofMillis(500L));
fileSystemWatcher.addSourceDirectory(new File(folderPath));
fileSystemWatcher.addListener(dataFileChangeListener);
fileSystemWatcher.start();
logger.info("dest Data fileSystemWatcher");
return fileSystemWatcher;
}
@PreDestroy
public void onDestroy() throws Exception {
destDataWatcher().stop();
}
}
And here is my onchange event implementation :
@Component
public class LogsFileChangeListener implements FileChangeListener {
private Logger logger = LoggerFactory.getLogger(LogsFileChangeListener.class);
@Autowired
RabbitMQService rabbitMQService;
@Value("${application.scope}")
private String appScope;
@Value("${residents.rabbitmq.listener.ext.sync.exchange}")
private String extSyncExchange;
@Value("${residents.rabbitmq.listener.int.sync.exchange}")
private String intSyncExchange;
@Value("${residents.rabbitmq.listener.file.create.routingKey}")
private String routingKey;
@Override
public void onChange(Set<ChangedFiles> changeSet) {
for(ChangedFiles cfiles : changeSet){
for(ChangedFile cfile : cfiles){
if(cfile.getType().equals(ChangedFile.Type.ADD) || cfile.getType().equals(ChangedFile.Type.MODIFY) && !isLocked(cfile.getFile().toPath())){
String fileName = cfile.getFile().getName();
logger.info("Operation: " + cfile.getType()
+ " On Sync Data file: "+ fileName + " is done");
RabbitMessageModel rabbitMessageModelLog = new RabbitMessageModel();
rabbitMessageModel.setFileName(fileName);
rabbitMessageModel.setFolderPath(Utils.getSyncFolderPath(appScope.equalsIgnoreCase("external") ? Constants.DIR_TYPE.EXT_DEST_DATA : Constants.DIR_TYPE.INT_DEST_DATA));
rabbitMQService.send(rabbitMessageModelLog,routingKey, appScope.equalsIgnoreCase("external") ? extSyncExchange : intSyncExchange);
}
}
}
}
private boolean isLocked(Path path) {
try (FileChannel ch = FileChannel.open(path, StandardOpenOption.WRITE); FileLock lock = ch.tryLock()) {
return lock == null;
} catch (IOException e) {
return true;
}
}
}
I've found the root cause by the folder which store file be locked by writer process. With high frequency, it will be locked until writer complete. So that, I've change my code to another way. I use common.io package to watching folder and just lock file which being write not lock folder. So that, my writer app and listener app can work parallel