I have this very simple stream to process a file - just a FileIO.FromFile
source, a pass-through flow, and a Last
sink:
var source = FileIO.FromFile(new FileInfo(fileName));
var flow = Flow.FromFunction<ByteString, ByteString>(x =>
{
Log.Info(x.Count.ToString());
return x;
});
var sink = Sink.Last<ByteString>();
var runnable = source.Via(flow).ToMaterialized(sink, Keep.Right);
var result = runnable.Run(Context.Materializer()).Result;
The stream runs as expected: the logger spams out the bytestring sizes until the file source is completely exhausted.
Now, I change the sink to use First instead of Last
var source = FileIO.FromFile(new FileInfo(fileName));
var flow = Flow.FromFunction<ByteString, ByteString>(x =>
{
Log.Info(x.Count.ToString());
return x;
});
var sink = Sink.First<ByteString>();
var runnable = source.Via(flow).ToMaterialized(sink, Keep.Right);
var result = runnable.Run(Context.Materializer()).Result;
The documentation for "First" states "cancels after receiving one element", which I assumed meant the sink signals a cancel up the stream, which would close the source. But when this stream is run, two things happen.
1) I get the following debug log message
[DEBUG][17/05/2018 13:55:16][Thread 0004][akka://Demo/user/DATReader/StreamSupervisor-0/Flow-0-1-fileSource] Unhandled message from akka://Demo/user/DATReader/StreamSupervisor-0/Flow-0-0-unknown-operation : Akka.Streams.Actors.Cancel
and
2) The file is locked, so any further attempt to read it fails with an access denied exception.
I also tried using Take(1)
on the source, but the same effect is seen.
My question is: how do I read only the first n bytes from a file and shut down the stream gracefully so that any lock (obtained by FileIO.FromFile) is released?
In my case, there is no such error. Try using sharedKillSwitch to control completion. Documentation is here about Dynamic stream handling
var sharedKillSwitch = KillSwitches.Shared("my-kill-switch");
var source = FileIO.FromFile(new FileInfo(fileName), chunkSize: 1024)
.Via(sharedKillSwitch.Flow<ByteString>());
var sink = Sink.First<ByteString>();
var runnable = source.Select(x => {
Log.Info(x.Count.ToString());
sharedKillSwitch.Shutdown();
return x;
})
.ToMaterialized(sink, Keep.Right);
var result = runnable.Run(materializer).Result;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.