"java.io.FileNotFoundException: No files matched spec" thought文件已成功写入
"java.io.FileNotFoundException: No files matched spec" althought file is successfully written to
Edit -- the error seems to come not from the write block but from
the output block, which is even stranger. Modified to reflect my
investigations.
Edit2 -- solved - the issue is due to an improperly closed writer, for some reason only triggered in the DataflowRunner but not in the DirectRunner. Will add an answer later today when I find the time. If anyone has an insight on why the writer is closed in the DirectRunner but not in the DataflowRunner, I am very interested.
考虑以下 Java 2.5.0 数据流代码:
BlobId blobTranscriptId = BlobId.of(tempBucket, fileName);
BlobInfo blobTranscriptInfo = BlobInfo.newBuilder(blobTranscriptId).build();
try (WriteChannel writer = storageClient.writer(blobTranscriptInfo)) {
LOG.info("Writing file");
writer.write(ByteBuffer.wrap(currentString.toString().getBytes(UTF_8)));
processContext.output("gs://" + tempBucket + "/" + fileName)
LOG.info("Wrote " + fileName);
} catch (Exception e) {
LOG.warn("Error caught while writing content : " + ExceptionUtils.getStackTrace(e));
}
当 运行 在本地(在 DirectPipeline 中)时,此代码工作正常且没有错误。
然而,当 运行 在 Dataflow 中(在 DataflowRunner 中)时,我们注意到一个奇怪的行为:
- 文件是在请求的存储桶上创建的,具有请求的内容和文件名
- 一个
UserCodeException: java.io.FileNotFoundException: No files matched spec
被捕获在 processContext.output
行。
在 google gcp“没有文件匹配规范” 上搜索没有 return 一个结果。查看 org.apache.beam.sdk.io.FileSystems.java
中的源代码(在第 173 行声明的错误)并没有多大帮助。
使用调试器执行后显示使用 DirectRunner,代码 从未调用 FileIO.MatchAll
,这是错误的来源。但是,对于 DataflowRunner,错误会以某种方式触发。没有理由将输出字符串解释为文件路径,因为堆栈跟踪表明错误发生在这个阶段,它被声明为输出 PCollection<String>
.
为什么 FileNotFoundException
即使文件显然已创建且内容正确,但仍会启动?
一些可能有帮助的附加信息:
- 文件名是通过 UUID4
UUID.randomUUID()
生成的,这意味着它包含“-”字符以及长文件名。然而,这应该不是问题,因为 1) 它在 DirectRunner 中工作 2) 文件是实际创建的
- 接下来的阶段是
TextIO.readAll()
- 堆栈跟踪(为保护隐私而略作修改):https://pastebin.com/wumha4ZZ
补充调查:
- 将输出更改为指向现有文件的固定字符串
processContext.output("gs://" + tempBucket + "/" + alreadyExistingFileName);
不会触发错误。然后我怀疑它可能(以某种方式)是由于写入操作和存储桶确认文件的时间之间的延迟错误造成的。
- 在
write
和 output
之间添加 Thread.sleep(15000)
并不能解决问题。延迟似乎不是这里的问题。
更详细地查看堆栈跟踪显示错误通过 FileIO
发生,它本身通过此错误之后的 TextIO
阶段调用。
发生的事情是,在我上面的代码中,我没有在 将字符串输出到 TextIO
之前关闭编写器 writer.close()
,而是 after(通过 try(Writer writer){}
块)。由于桶在其编写器关闭之前不会注册文件,因此 TextIO 无法找到文件并启动 FileNotFoundException
。这反过来会关闭 try
块并启动 writer.close()
,这就是文件最终仍出现在存储桶中的原因。
出于某种我不知道的原因,通过本地 DirectLauncher
启动时不会发生这种情况。
Edit -- the error seems to come not from the write block but from the output block, which is even stranger. Modified to reflect my investigations.
Edit2 -- solved - the issue is due to an improperly closed writer, for some reason only triggered in the DataflowRunner but not in the DirectRunner. Will add an answer later today when I find the time. If anyone has an insight on why the writer is closed in the DirectRunner but not in the DataflowRunner, I am very interested.
考虑以下 Java 2.5.0 数据流代码:
BlobId blobTranscriptId = BlobId.of(tempBucket, fileName);
BlobInfo blobTranscriptInfo = BlobInfo.newBuilder(blobTranscriptId).build();
try (WriteChannel writer = storageClient.writer(blobTranscriptInfo)) {
LOG.info("Writing file");
writer.write(ByteBuffer.wrap(currentString.toString().getBytes(UTF_8)));
processContext.output("gs://" + tempBucket + "/" + fileName)
LOG.info("Wrote " + fileName);
} catch (Exception e) {
LOG.warn("Error caught while writing content : " + ExceptionUtils.getStackTrace(e));
}
当 运行 在本地(在 DirectPipeline 中)时,此代码工作正常且没有错误。
然而,当 运行 在 Dataflow 中(在 DataflowRunner 中)时,我们注意到一个奇怪的行为:
- 文件是在请求的存储桶上创建的,具有请求的内容和文件名
- 一个
UserCodeException: java.io.FileNotFoundException: No files matched spec
被捕获在processContext.output
行。
在 google gcp“没有文件匹配规范” 上搜索没有 return 一个结果。查看 org.apache.beam.sdk.io.FileSystems.java
中的源代码(在第 173 行声明的错误)并没有多大帮助。
使用调试器执行后显示使用 DirectRunner,代码 从未调用 FileIO.MatchAll
,这是错误的来源。但是,对于 DataflowRunner,错误会以某种方式触发。没有理由将输出字符串解释为文件路径,因为堆栈跟踪表明错误发生在这个阶段,它被声明为输出 PCollection<String>
.
为什么 FileNotFoundException
即使文件显然已创建且内容正确,但仍会启动?
一些可能有帮助的附加信息:
- 文件名是通过 UUID4
UUID.randomUUID()
生成的,这意味着它包含“-”字符以及长文件名。然而,这应该不是问题,因为 1) 它在 DirectRunner 中工作 2) 文件是实际创建的 - 接下来的阶段是
TextIO.readAll()
- 堆栈跟踪(为保护隐私而略作修改):https://pastebin.com/wumha4ZZ
补充调查:
- 将输出更改为指向现有文件的固定字符串
processContext.output("gs://" + tempBucket + "/" + alreadyExistingFileName);
不会触发错误。然后我怀疑它可能(以某种方式)是由于写入操作和存储桶确认文件的时间之间的延迟错误造成的。 - 在
write
和output
之间添加Thread.sleep(15000)
并不能解决问题。延迟似乎不是这里的问题。
更详细地查看堆栈跟踪显示错误通过 FileIO
发生,它本身通过此错误之后的 TextIO
阶段调用。
发生的事情是,在我上面的代码中,我没有在 将字符串输出到 TextIO
之前关闭编写器 writer.close()
,而是 after(通过 try(Writer writer){}
块)。由于桶在其编写器关闭之前不会注册文件,因此 TextIO 无法找到文件并启动 FileNotFoundException
。这反过来会关闭 try
块并启动 writer.close()
,这就是文件最终仍出现在存储桶中的原因。
出于某种我不知道的原因,通过本地 DirectLauncher
启动时不会发生这种情况。