Repository: dotnet/roslyn
File: src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs (C#)

Code before:

    private readonly IAsynchronousOperationListener _asyncListener;
    private readonly CancellationTokenSource _disposalTokenSource;
    private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService;

    protected bool _isQueueCreated;

    protected abstract string GetFeatureAttribute();
    protected abstract bool? GetRefreshSupport(ClientCapabilities clientCapabilities);
    protected abstract string GetWorkspaceRefreshName();

    public AbstractRefreshQueue(
        IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider,
        LspWorkspaceRegistrationService lspWorkspaceRegistrationService,
        LspWorkspaceManager lspWorkspaceManager,
        IClientLanguageServerManager notificationManager)
    {
        _isQueueCreated = false;
        _asyncListener = asynchronousOperationListenerProvider.GetListener(GetFeatureAttribute());
        _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService;
        _disposalTokenSource = new();
        _lspWorkspaceManager = lspWorkspaceManager;
        _notificationManager = notificationManager;
    }

    public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken)
    {
        Initialize(clientCapabilities);
        return Task.CompletedTask;
    }

    public void Initialize(ClientCapabilities clientCapabilities)
    {
        if (_refreshQueue is null && GetRefreshSupport(clientCapabilities) is true)
        {
            // Only send a refresh notification to the client every 2s (if needed) in order to avoid
            // sending too many notifications at once.  This ensures we batch up workspace notifications,
            // but also means we send soon enough after a compilation-computation to not make the user wait
            // an enormous amount of time.
            _refreshQueue = new AsyncBatchingWorkQueue<DocumentUri?>(
                delay: TimeSpan.FromMilliseconds(2000),
                processBatchAsync: (documentUris, cancellationToken)
                    => FilterLspTrackedDocumentsAsync(_lspWorkspaceManager, _notificationManager, documentUris, cancellationToken),
                equalityComparer: EqualityComparer<DocumentUri?>.Default,
                asyncListener: _asyncListener,
                _disposalTokenSource.Token);
            _isQueueCreated = true;
            _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged;
        }
    }


Review comment (suggestion):
I'm curious to know some details about these efforts. Is that somehow related to the new runtime async stuff? IIRC, this used to produce warning along the lines of "this async method is lacking awaits and will run synchronously".

Code after:

    private readonly IAsynchronousOperationListener _asyncListener;
    private readonly CancellationTokenSource _disposalTokenSource;
    private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService;

    protected bool _isQueueCreated;

    protected abstract string GetFeatureAttribute();
    protected abstract bool? GetRefreshSupport(ClientCapabilities clientCapabilities);
    protected abstract string GetWorkspaceRefreshName();

    public AbstractRefreshQueue(
        IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider,
        LspWorkspaceRegistrationService lspWorkspaceRegistrationService,
        LspWorkspaceManager lspWorkspaceManager,
        IClientLanguageServerManager notificationManager)
    {
        _isQueueCreated = false;
        _asyncListener = asynchronousOperationListenerProvider.GetListener(GetFeatureAttribute());
        _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService;
        _disposalTokenSource = new();
        _lspWorkspaceManager = lspWorkspaceManager;
        _notificationManager = notificationManager;
    }

    public async Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken)
    {
        Initialize(clientCapabilities);
    }

    public void Initialize(ClientCapabilities clientCapabilities)
    {
        if (_refreshQueue is null && GetRefreshSupport(clientCapabilities) is true)
        {
            // Only send a refresh notification to the client every 2s (if needed) in order to avoid
            // sending too many notifications at once.  This ensures we batch up workspace notifications,
            // but also means we send soon enough after a compilation-computation to not make the user wait
            // an enormous amount of time.
            _refreshQueue = new AsyncBatchingWorkQueue<DocumentUri?>(
                delay: TimeSpan.FromMilliseconds(2000),
                processBatchAsync: (documentUris, cancellationToken)
                    => FilterLspTrackedDocumentsAsync(_lspWorkspaceManager, _notificationManager, documentUris, cancellationToken),
                equalityComparer: EqualityComparer<DocumentUri?>.Default,
                asyncListener: _asyncListener,
                _disposalTokenSource.Token);
            _isQueueCreated = true;
            _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged;
        }
    }

    protected virtual void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e)