user1323245
user1323245

Reputation: 638

Program halts / blocks when calling method that returns TaskCompletionSource.Task

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

Answers (0)

Related Questions