Reputation: 6578
I have a method
public Task<Task> DoSomeWorkOnARemoteMachine()
which, very descriptively, executes some work on a remote machine by:
The reason I used Task<Task>
is because the first Task<>
is for the queueing of the message; while the inner Task
is completed when the work has been completed on the remote machine (i.e. when the message from the agent has been received). Any exceptions which the remote agent caught during execution of the work are passed along with the completion message and are re-thrown when the inner Task
completes.
To call this method I use:
await await DoSomeWorkOnARemoteMachine();
which would wait for the message to be queued to execute the job, as well as to complete the job and receive any exceptions. However, if I was not interested in whether the job completed on the remote agent or not, I might call it as follows:
await DoSomeWorkOnARemoteMachine();
which would not await
the inner Task
. However, the inner Task
(which receives the message from the remote agent, and re-throws the exceptions) would still execute at some point. I feel that this is a bit of a waste and I would like to avoid executing it when I don't await
for the results.
My question is thus: is it possible for a Task
to "know" whether it is being await
ed and not execute if it is not, or execute some other code path (such as an empty Task
body).
I do realize that there are alternatives that I could implement, such as passing a "fire and forget" flag, or adding an overload for "fire and forget". It would be great though if I could implement this without the client API changing
Answers involving other projects which implement this sort of remote work execution would also be great!
Upvotes: 10
Views: 259
Reputation: 245076
I think the way you're doing this is quite confusing. It's not clear at all what the Task<Task>
is supposed to mean. What I would do instead is to make your method return something like Task<Work>
. The Work
type would then have a method like GetResultAsync()
, which would return the Task
that represents the execution of the work on the remote machine.
This way, you have code that has much clearer meaning and you can also easily recognize whether to process the response, based on whether GetResultAsync()
was called or not.
Upvotes: 2
Reputation: 61744
That is a very interesting question. Yet, if I understood it correctly, I believe this is impossible, in the way you presented it, because it doesn't make sense (IMO). Let's look at the following model (please let me know if I got it wrong):
static async Task<Task> DoSomeWorkOnARemoteMachine()
{
// Point X:
await Task.Delay(1000);
// Point Y:
Console.WriteLine("request sent");
var taskInner = Task.Delay(2000);
// Point A: here you want to know if there's an await at Point B
return taskInner;
}
static async Task Test()
{
var taskOuter = DoWorkAsync();
// Point Z:
await taskOuter;
// Point B:
await taskOuter.Result; // await taskInner
Console.WriteLine("request received");
}
At the Point A, you like to know if there's an await
at the Point B. But at this moment, the Point B is still in the future, it hasn't happened yet. You'd need a time machine for that :)
[UPDATE] In the same way, at the Point X you cannot know about the await
at the Point Z, because the code flow has not reached Z yet.
However, when at Y, in theory you possibly could know about the await
at Z (still not about B). Although, I don't know if it's technically possible to get a hold of such information.
Upvotes: 3
Reputation: 3006
I dont think it's easily or efficiently achievable (playing with Task.GetAwaiter is a bad idea, and it will not be accessible from inside your function, see Noseratio's answer). Here is alternative solutions :
Solution n°1 : Function parameter for Task
execution
await DoSomeWorkOnARemoteMachine(false) //Indicates that DoSomeWork shouldn't be executed
Solution n°2 : Explicit Task Execution
Task t = await DoSomeWorkOnARemoteMachine() ;
t.Start(); // For example, if you want to execute the resulting Task.
// You can also dispatch it to an other thread, etc...
Upvotes: 3