'Wrap a call in a task, to add a timeout?

We have an SDK that we are using from a 3rd-party. We have no access or insight into the code at all, or ability to change anything with it.

We're running into a problem where we make a bunch of updates to an object in the SDK, and then when we call their .Commit() method, it goes off into oblivion, and never comes back. Their Commit has no timeout parameter or anything to tell it - hey, give up already.

So when their code goes into oblivion, so too does our program.

I'm wondering if there is a way that I can use async/await stuff to essentially add a timeout to the call to their Commit. I've not done any of async stuff before though, so I'm not sure this is possible. I would still need it to be synchronous in terms of our program's process flow.

Essentially, I'm envisioning something along the lines of

    ... <setting a bunch of sdkObject fields> ...

    var done = false;

    await new Task(function(ref sdkObject, ref done) {
            sdkObject.Commit();
            done = true;
        }, timeout: 60000);

    if (done) {
        <perform post-success code>
    } else {
        <perform post-failure code>
    }

This then would allow us to artificially put a timeout around their Commit method, so that even if it goes off into oblivion, never to be seen again, our code would at least be able to try to wrap up gracefully and continue on with the next record to process.



Solution 1:[1]

I'm wondering if there is a way that I can use async/await stuff to essentially add a timeout to the call to their Commit.

Well... sort of.

You can wrap the call into a Task.Run and then use WaitAsync to create a cancelable wait, as such:

try {
  await Task.Run(() => sdkObject.Commit()).WaitAsync(TimeSpan.FromSeconds(60));
  <perform post-success code>
} catch (TimeoutException {
  <perform post-failure code>
}

However, this will probably not work as expected. WaitAsync gives you a way to cancel the wait - it doesn't give you a way to cancel Commit. The Commit will just keep on executing - it's just that your application no longer cares if or when or how it complete.

The library you're using may or may not like having another Commit called when the last one is still running. So this may not actually work for your use case.

The only way to truly cancel uncancelable code is to wrap the code into a separate process and kill the process when you want to force cancellation. This is quite involved but sometimes you have no choice.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Stephen Cleary