0

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.

user1323245
  • 638
  • 1
  • 8
  • 20
  • Please use a debugger to check what the application is actually doing. "goes quiet" is not very descriptive. Most importantly, does the task ever complete? Are any threads blocked inside your own code? Do you ever use a blocking call, like `.Result` or `.Wait()`? These are notorious for causing deadlocks if you are not careful. – JonasH Aug 08 '23 at 06:30
  • Is it a Windows Forms application or something that has task context sensititivity. If so, awaits usually need ConfigureAwait(false) – Marko Lahma Aug 08 '23 at 13:32
  • That socket code is horrifying. That said, you'll probably need to post a minimal repro to determine the issue. – Stephen Cleary Aug 09 '23 at 10:20
  • @MarkoLahma It's a Core Console application. – user1323245 Aug 09 '23 at 18:06
  • @StephenCleary Yes. As much as I'd love to solve this issue, we ended up dropping Quartz and use a simple Task.Delay() as a "scheduler" since that is likely to be good enough for us for now. I doubt I'll have the time to research this more now that we have an alternative solution that works. Should I delete the question perhaps? – user1323245 Aug 09 '23 at 18:15

0 Answers0