Reputation: 638
Problem:
Application "goes quiet" when awaiting a method that returns TaskCompletionSource.Task
from inside JobWasExecuted()
that is being called by Quartz.
Scenario:
I have a program that use Quartz to schedule a job. Since I simply want a "notification" in order to execute more work to be done, I have opted to have a type inherit from JobListenerSupport
and override the Task JobWasExecuted(IJobExecutionContext context, JobExecutionException? jobException, CancellationToken cancellationToken = default)
method.
The work to be done includes calling methods on other types, where the methods are wrapping an event-based pattern to transform it into a task-based pattern by utilizing TaskCompletionSource
, similar to the code below (actual code):
public Task<List<ScanResult>> Subscribe(ScanRequest scanRequest)
{
var requestId = CreateRequestId();
var taskCompletionSource = new TaskCompletionSource<List<ScanResult>>();
scanRequestResultsByReqId.TryAdd(requestId, new ScanRequestResult(scanRequest, taskCompletionSource));
ClientSocket.reqScannerSubscription(
requestId,
scanRequest.ScannerSubscription,
scannerSubscriptionOptions: null,
scanRequest.ScannerSubscriptionOptions);
return taskCompletionSource.Task;
}
These methods are all ultimate called from JobWasExecuted()
, similiar to the code below.
public override async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException? jobException, CancellationToken cancellationToken = default)
{
await Do();
// ...
await base.JobWasExecuted(context, jobException, cancellationToken);
}
public async Task Do()
{
var scanResults = await scanner.Subscribe(CreateScanRequest());
// ...
}
When a call to any method returning a TaskCompletionSource.Task
, like the one in Do()
, is awaited at any point from the JobWasExecuted()
method the application just... goes quiet.
Since the whole application seems to work just fine if Quartz and the JobWasExecuted()
method is bypassed by manually calling the Do()
from application entry, it seems to hint that there is some shenaningans going on with threads that I don't understand.
What am I missing?
Update / Edit:
1: I'm not using any .Result
or .Wait
or anything similar anywhere.
2: When I use the debugger to pause the application after the above scenario has made the application "go quiet" it always takes me to the following loop inside a the third party library I'm using, the one producing events I'm consuming.
while (eClientSocket.IsConnected())
{
if (!eClientSocket.IsDataAvailable())
{
Thread.Sleep(1);
continue;
}
if (!putMessageToQueue())
break;
}
Everything worked fine when using good old callbacks. It was when I switched to using TaskCompletionSource that this problem showed up. And it's not a problem when not the Quartz JobWasExecuted()
callback.
Upvotes: 0
Views: 48