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“No files matched spec” 上搜索没有返回单个结果。查看 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);
不会触发错误。然后我怀疑这可能(以某种方式)是由于写入操作和存储桶确认文件的时间之间的延迟错误造成的。 - 添加
Thread.sleep(15000)
在write
之间和output
不能解决问题。延迟似乎不是这里的问题。
最佳答案
查看堆栈跟踪的更多细节表明错误是通过 FileIO
发生的,它本身是通过此之后的 TextIO
阶段调用的。
发生的事情是,在我上面的代码中,我没有关闭编写器 writer.close()
before 将字符串输出到 TextIO
,但是之后(通过 try(Writer writer){}
block )。由于存储桶在其编写器关闭之前不会注册文件,因此 TextIO 无法找到文件并启动 FileNotFoundException
。这反过来会关闭 try
block 并启动 writer.close()
,这就是为什么文件最后仍然出现在存储桶中的原因。
出于某种我不知道的原因,通过本地 DirectLauncher
启动时不会发生这种情况。
关于java - "java.io.FileNotFoundException: No files matched spec"虽然文件已成功写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51415426/