Azure / azure-storage-cpp

Microsoft Azure Storage Client Library for C++
http://azure.github.io/azure-storage-cpp
Apache License 2.0
131 stars 147 forks source link

question on catch exception for async operations #402

Open sherlockwu opened 3 years ago

sherlockwu commented 3 years ago

Hi all,

I have a question related to catching exception for azure blob async upload operations. Here is my sync version: (upload if not exist)

try {
        azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(
                storage_connection_string);
        azure::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client();
        azure::storage::cloud_blob_container container = blob_client.get_container_reference(U("my-sample-container"));

        azure::storage::cloud_block_blob blob4 = container.get_block_blob_reference(U("my-blob-4"));
        azure::storage::access_condition condition4 = azure::storage::access_condition::generate_if_not_exists_condition();
        azure::storage::blob_request_options options4;
        azure::storage::operation_context context4;
        blob4.upload_text(U("test new overwrite text"), condition4, options4, context4);
    }
    catch (const std::exception &e) {
        std::cout << U("Error: ") << e.what() << std::endl;
    }

The catch part will catch the exception if the blob already exists.

My question is:

  1. how should I catch the exception for upload_text_async() ? simply replace upload_text by upload_text_async cannot catch the exception.
  2. is there a way I can get the return "message" of async or sync operations, instead of by throwing exceptions?

Thank you, Kan

Jinming-Hu commented 3 years ago

how should I catch the exception for upload_text_async() ? simply replace upload_text by upload_text_async cannot catch the exception.

auto async_task = blob4.upload_text_async(U("test new overwrite text"), condition4, options4, context4);
try {
  async_task.get();  // block until the task is finished.
}
catch (const std::exception& e) {
  std::cout << U("Error: ") << e.what() << std::endl;
}
sherlockwu commented 3 years ago

Thanks for your reply!

Uhm, would that piece of code become sync upload then?

Jinming-Hu commented 3 years ago

is there a way I can get the return "message" of async or sync operations, instead of by throwing exceptions?

The return type for upload_text and unpload_text_async is void, so there isn't any "message".

Take cloud_blob::exists() for example, the sync version returns a bool. So if the blob actually exists, that function returns true. If the blob doesn't exists, the function returns false. If any error happens (like authentication error), the function will throw. For async version, calling .get() on the returned task will return true or false or throw.

Jinming-Hu commented 3 years ago

Uhm, would that piece of code become sync upload then?

In your sample code, yes. Because there's only one task. You can start a bunch of asynchronous tasks and then wait for them in one thread, like

std::vector<pplx::task<T>> tasks;
tasks.emplace_back(an_async_function());

for (auto& t: tasks) {
    t.get();
}

Note that it's your responsibility to observe every potential exception in async task. So if you're pretty sure some async task won't throw, you don't have to call .get().

Jinming-Hu commented 3 years ago

@sherlockwu BTW, this project has been deprecated in favor of our new version of storage SDK. So if you're starting a new project, you may want to try the new sdk.

sherlockwu commented 3 years ago

Thanks for your reply.

Perhaps I could talk more about our expected behaviors.

We'd like to

  1. async upload some blobs (if they do not exist).
  2. then know whether the uploads succeed or not (not may because blobs already exist);
  3. no matter succeed or not, we'd like to do some follow-up work upon a upload complete.

Now, I'm using .then() to implement the follow-up works. However, turns out we cannot know the uploads succeeded or not. What would you suggest us to implement with the APIs? thanks

Thanks for telling us about storage SDK. Would our need be easier to implement with azure-sdk? Thanks

Jinming-Hu commented 3 years ago

@sherlockwu

Every API has an overload which takes an access_condition as parameter, where you can set if-not-exist condition, so that the operation will fail and throw exception if the blob already exists. (Which I see you already did in your sample code)

In the .then() continuation task, you can tell if the last operation succeeded or not by checking if there's an exception. Like

auto t = blob4.upload_text_async(U("test new overwrite text"), condition4, options4, context4).then([](pplx::task<void> previous_task) {
  try {
    previous_task.get();
  }
  catch (azure::storage::storage_exception& e)
  {
    // failed, do clean up work here
  }
  // not failed, do other work
});
t.wait();  // This waits for the continuation task (defined by the lambda).
Jinming-Hu commented 3 years ago

Would our need be easier to implement with azure-sdk?

The new SDK only supports synchronous API, which is much easier to use.

Asynchronous task in this sdk is less easy to comprehend and is error-prune. In addition, although the API interface is asynchronous, it uses a thread-pool under the hood, so there's really no performance gain here. Actually our new SDK has much better performance than this old sdk.

sherlockwu commented 3 years ago

Got you.

That sample code looks like what we indeed need. Let me have a try and get back to you.

Thanks a lot for the help.