0

I am uploading a single file to an SFTP server using Alpakka but once the file is uploaded and I have gotten the success response the Sink stays open, how do I drain it?

I started off with this:

val sink = Sftp.toPath(path, settings, false)
val source = Source.single(ByteString(data))
​
source
  .viaMat(KillSwitches.single)(Keep.right)
  .toMat(sink)(Keep.both).run()
  .map(_.wasSuccessful)

But that ends up never leaving the map step. I tried to add a killswitch, but that seems to have had no effect (neither with shutdown or abort):

val sink = Sftp.toPath(path, settings, false)
val source = Source.single(ByteString(data))
​
val (killswitch, result) = source
  .viaMat(KillSwitches.single)(Keep.right)
  .toMat(sink)(Keep.both).run()

result.map {
  killswitch.shutdown()
  _.wasSuccessful
}

Am I doing something fundamentally wrong? I just want one result.

EDIT The settings sent in to toPath:

SftpSettings(InetAddress.getByName(host))
    .withCredentials(FtpCredentials.create(amexUsername, amexPassword))
    .withStrictHostKeyChecking(false)
spydon
  • 9,372
  • 6
  • 33
  • 63
  • Which settings did you use? – Andrii Stefaniv Oct 26 '18 at 09:41
  • @AndriiStefaniv edited my question to add the settings. – spydon Oct 26 '18 at 11:39
  • Try putting `Await.result(result, Duration.Inf)` at the end to block until flow is completed. You don't need KillSwitch. – expert Oct 26 '18 at 11:49
  • I don't see how it would help making it synchronous, but I tried and it works. @expert why does the flow never finish without the Away? – spydon Oct 26 '18 at 12:01
  • Can't edit the comment anymore: Await* – spydon Oct 26 '18 at 12:07
  • Aaah I'm so stupid. The output that I expected after the map obviously came way before and garbled into the sftp libraries debug output. What made me think that the map wasn't done was because of the ActorSystem not being terminated so the program didn't terminate. Thank you everybody for your help! – spydon Oct 26 '18 at 12:23

2 Answers2

2

By asking you to put Await.result(result, Duration.Inf) at the end I wanted to check the theory expressed by A. Gregoris. Thus it's either

  • your app exits before Future completes or
  • (if you app does't exit) function in which you do this discards result

If your app doesn't exit you can try using result.onComplete to do necessary work.

expert
  • 29,290
  • 30
  • 110
  • 214
  • Worth mentioning too that the confusion came from me forgetting to terminate the ActorSystem. – spydon Oct 26 '18 at 12:26
  • 1
    Ah yeah, then you can call `system.terminate` in handler of `onComplete` and prevent app from prematurely finishing by waiting on `Await.result(system.whenTerminated, Duration.Inf)` – expert Oct 26 '18 at 12:29
1

I cannot see your whole code but it seems to me that in the snippet you posted that result value is a Future that is not completing before the end of your program execution and that is because the code in the map is not being executed either.

  • It is a Future indeed, it's a Future[IOResult]. And the code in the `map` is being executed. – spydon Oct 26 '18 at 11:37
  • I see that your user is new here, a friendly tip is to use the comment function and not the answer function before you know the answer, otherwise you will likely get down votes. :) – spydon Oct 26 '18 at 11:46