ファイルの追加についてディレクトリを監視するコードがあります。新しいファイルがディレクトリに追加されるたびに、ファイルの内容が選択されkafkaで公開され、その後ファイルが削除されます。
これは、単一の要求を行うときに機能しますが、コードをjMeterから5または10のユーザー要求にかけるとすぐに、コンテンツはkafkaで正常に公開されますが、コードを削除できませんファイルFileSystemException
を取得し、The process cannot access the file because it is being used by another process.
。
私は見ることができないいくつかの並行性の問題があると思います。
public void monitor() throws IOException, InterruptedException {
Path faxFolder = Paths.get(TEMP_FILE_LOCATION);
WatchService watchService = FileSystems.getDefault().newWatchService();
faxFolder.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
boolean valid = true;
do {
WatchKey watchKey = watchService.take();
for (WatchEvent<?> event : watchKey.pollEvents()) {
if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
String fileName = event.context().toString();
publishToKafka(new File(TEMP_FILE_LOCATION + fileName).toPath(), "topic");
}
}
valid = watchKey.reset();
} while (valid);
}
private void publishToKafka(Path path, String topic) {
try (BufferedReader reader = Files.newBufferedReader(path)) {
String input = null;
while ((input = reader.readLine()) != null) {
kafkaProducer.publishMessageOnTopic(input, topic);
}
} catch (IOException e) {
LOG.error("Could not read buffered file to send message on kafka.", e);
} finally {
try {
Files.deleteIfExists(path); // This is where I get the exception
} catch (IOException e) {
LOG.error("Problem in deleting the buffered file {}.", path.getFileName(), e);
}
}
}
例外ログ:
Java.nio.file.FileSystemException: D:\upload\notif-1479974962595.csv: The process cannot access the file because it is being used by another process.
at Sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at Sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at Sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at Sun.nio.fs.WindowsFileSystemProvider.implDelete(Unknown Source)
at Sun.nio.fs.AbstractFileSystemProvider.deleteIfExists(Unknown Source)
at Java.nio.file.Files.deleteIfExists(Unknown Source)
at com.panasonic.mdw.core.utils.MonitorDirectory$FileContentPublisher.publishToKafka(MonitorDirectory.Java:193)
at com.panasonic.mdw.core.utils.MonitorDirectory$FileContentPublisher.sendData(MonitorDirectory.Java:125)
at com.panasonic.mdw.core.utils.MonitorDirectory$FileContentPublisher.run(MonitorDirectory.Java:113)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at Java.lang.Thread.run(Unknown Source)
コードを見ると、あるファイルがスレッドによって再び公開され、別のスレッドがそれを公開のために選択しているようです。だから誰もそれを削除できません。並行性の問題のみである必要があります。基準に基づいてコードを再設計する必要があります。同時に実行できるステップと実行できないステップ。プロセス全体のステップは次のとおりです。
また、ファイルが選択された瞬間に、それをバッファに読み込み、削除してから公開を続行できます。これにより、メインスレッドがこのファイルを他のスレッドに割り当てないようにします。
次のスレッドと同様の問題がありました: Multithreading on Queue 動的に作成されたファイルをキューサービスにアップロードしようとして、解決するのに2日かかりました。 Holger のおかげで、ロックが発生する上記の回答は、別のスレッドによる読み取り時に作成が完全に行われなかったためである可能性があるため、多くの時間を節約できました。
私の最初の解決策は、インターネットから多くのことがわかったとき、次のとおりでした。
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
//queueUploadFile(child);
if (kind == ENTRY_CREATE) {
uploadToQueue(this.queueId, child);
}
私はそれを次のように変更しました:
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
//queueUploadFile(child);
if (kind == ENTRY_MODIFY) {
uploadToQueue(this.queueId, child);
}
そして、すべてが完璧に機能します。 「何らかの形で」複数のENTRY_MODIFYイベントの起動(重複ファイルのアップロード)を処理するために、uploadToQueue()メソッド内のファイルをアップロードしたら削除します。
上記の貢献に基づいて取られた私のアプローチが、同様の問題を持つ他の人にも役立つことを願っています。