Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible clarification for long-running work advice #85

Open
brantburnett opened this issue Jan 24, 2022 · 1 comment
Open

Possible clarification for long-running work advice #85

brantburnett opened this issue Jan 24, 2022 · 1 comment

Comments

@brantburnett
Copy link

brantburnett commented Jan 24, 2022

I'm not sure if it may add more confusion than it's worth, but should an exception for a long-running asynchronous process be included for clarity? By long-running async process I mean a process that runs using async/await so it doesn't block any thread pool threads but which executes for an extended period of time. To my understanding, this pattern is acceptable, though it comes with other complexities.

I've definitely encountered cases where the advice on long-running work was interpreted to also include this pattern. I've seen this pattern used with Task.Factory.StartNew and TaskCreationOptions.LongRunning in the false assumption it puts all the work on a separate thread. In reality, it makes a thread just for startup, and then the first await puts the work back on the thread pool.

Example:

public class WorkerClass : IDisposable
{
    private static readonly TimeSpan WorkInterval = TimeSpan.FromMinutes(5);

    private readonly CancellationTokenSource _cts = new();

    public void Start()
    {
        bool restoreFlow = false;
        try
        {
            if (!ExecutionContext.IsFlowSuppressed)
            {
                ExecutionContext.SuppressFlow();
                restoreFlow = true;
            }

            _ = DoWorkAsync();
        }
        finally
        {
            if (restoreFlow)
            {
                ExecutionContext.RestoreFlow();
            }
        }
    }

    public async Task DoWorkAsync()
    {
        while (!_cts.IsCancellationRequested)
        {
            await Task.Delay(WorkInterval, _cts.Token);

            // Do async work here, assumption is the work item is not CPU intensive
        }
    }

    public void Dispose()
    {
        _cts.Cancel();
        _cts.Dispose();
    }
}
@RyanThomas73
Copy link

An example for these cases would be very helpful. Using Brant Burnett's example above:

Should the task from DoWorkAsync need to be held onto?
Should the task from DoWorkAsync be disposed?
Is it better to assign the DoWorkAsync() directly to a task field or should it be wrapped in Task.Run call which is also given the cancellation token?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants