1

I am writing a quick proof-of-concept for downloading images from Azure Blob Storage using the Java 12 Azure Storage SDK. The following code works properly when I convert it to synchronous. However, despite the subscribe() at the bottom of the code, I only see the subscription message. The success and error handlers are not firing. I would appreciate any suggestions or ideas.

Thank you for your time and help.

private fun azureReactorDownload() {

    var startTime = 0L
    var accountName = "abcd"
    var key = "09sd0908sd08f0s&&6^%"
    var endpoint = "https://${accountName}.blob.core.windows.net/$accountName
    var containerName = "mycontainer"
    var blobName = "animage.jpg"

    // Get the Blob Service client, so we can use it to access blobs, containers, etc.
    BlobServiceClientBuilder()
        // Container URL
        .endpoint(endpoint)
        .credential(
            SharedKeyCredential(
                accountName,
                key
            )
        )
        .buildAsyncClient()

        // Get the container client so we can work with our container and its blobs.
        .getContainerAsyncClient(containerName)

        // Get the block blob client so we can access individual blobs and include the path
        // within the container as part of the filename.
        .getBlockBlobAsyncClient(blobName)

        // Initiate the download of the desired blob.
        .download()
        .map { response ->
            // Drill down to the ByteBuffer.
            response.value()
        }
        .doOnSubscribe {
            println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Subscription arrived.")
            startTime = System.currentTimeMillis()
        }
        .doOnSuccess { data ->
            data.map { byteBuffer ->
                println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> READY TO WRITE TO THE FILE")
                byteBuffer.writeToFile("/tmp/azrxblobdownload.jpg")
                val elapsedTime = System.currentTimeMillis() - startTime
                println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Finished downloading blob in $elapsedTime ms.")
            }
        }
        .doOnError {
            println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Failed to download blob: ${it.localizedMessage}")
        }

        .subscribe()
}

fun ByteBuffer.writeToFile(path: String) {
    val fc = FileOutputStream(path).channel
    fc.write(this)
    fc.close()
}
A Bit of Help
  • 1,368
  • 19
  • 36

2 Answers2

1

I've worked with Microsoft and have a documented solution at the following link: https://github.com/Azure/azure-sdk-for-java/issues/5071. The person who worked with me provided very good background information, so it is more than just some working code.

I have opened a similar query with Microsoft for the downloadToFile() method in the Azure Java SDK v12, which is throwing an exception when saving to a file.

Here is the working code from that posting:

private fun azureReactorDownloadMS() {

    var startTime = 0L

    val chunkCounter = AtomicInteger(0)

    // Get the Blob Service client, so we can use it to access blobs, containers, etc.
    val aa = BlobServiceClientBuilder()
        // Container URL
        .endpoint(kEndpoint)
        .credential(
            SharedKeyCredential(
                kAccountName,
                kAccountKey
            )
        )
        .buildAsyncClient()

        // Get the container client so we can work with our container and its blobs.
        .getContainerAsyncClient(kContainerName)

        // Get the block blob client so we can access individual blobs and include the path
        // within the container as part of the filename.
        .getBlockBlobAsyncClient(kBlobName)
        .download()
        // Response<Flux<ByteBuffer>> to Flux<ByteBuffer>
        .flatMapMany { response ->
            response.value()
        }
        .doOnSubscribe {
            println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Subscription arrived.")
            startTime = System.currentTimeMillis()
        }
        .doOnNext { byteBuffer ->
            println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> CHUNK ${chunkCounter.incrementAndGet()} FROM BLOB ARRIVED...")
        }
        .doOnComplete {
            val elapsedTime = System.currentTimeMillis() - startTime
            println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Finished downloading ${chunkCounter.incrementAndGet()} chunks of data for the blob in $elapsedTime ms.")
        }
        .doOnError {
            println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Failed to download blob: ${it.localizedMessage}")
        }

        .blockLast()
}
A Bit of Help
  • 1,368
  • 19
  • 36
0

I see someone asking the same question 4 months ago and getting no answer:

Azure Blob Storage Java SDK: Why isn't asynchronous working?

I'm going to conjecture that this part of the JDK just isn't working right now. I wouldn't recommend using Azure's version of Java.

You should be able to accomplish it another way perhaps one of these answers: Downloading Multiple Files Parallelly or Asynchronously in Java

Philip Rego
  • 552
  • 4
  • 20
  • 35
  • Hmmm... I know that MS had issues in v10 and 11 of the SDK, and 12 is a prerelease, but I was hoping that something as basic as downloading a blob would work... So, it seems that there isn't a flaw in my code, but the SDK? – A Bit of Help Aug 20 '19 at 20:10
  • ya I think your code is fine although I'm not sure what value they want for endpoint. I think you should create an issue here you'll get better help https://github.com/Azure/azure-sdk-for-java/issues – Philip Rego Aug 20 '19 at 21:35
  • Thank you for the suggestion, Philip. I've opened a bug report and here is the link: https://github.com/Azure/azure-sdk-for-java/issues/5071. I will report what I learn... – A Bit of Help Aug 21 '19 at 06:09