Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 323f330

Browse files
committed
Ensure consistent task ordering using ContinueWith
Lock prevent tasks being executed at the same time but doesn't stop them being started out of order.
1 parent 976a47e commit 323f330

File tree

2 files changed

+21
-16
lines changed

2 files changed

+21
-16
lines changed

src/GitHub.TeamFoundation.14/Services/VSGitExt.cs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Linq;
3+
using System.Threading.Tasks;
34
using System.Collections.Generic;
45
using System.ComponentModel.Composition;
56
using GitHub.Models;
@@ -8,7 +9,6 @@
89
using GitHub.TeamFoundation.Services;
910
using Serilog;
1011
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
11-
using Task = System.Threading.Tasks.Task;
1212

1313
namespace GitHub.VisualStudio.Base
1414
{
@@ -24,7 +24,6 @@ public class VSGitExt : IVSGitExt
2424
readonly IGitHubServiceProvider serviceProvider;
2525
readonly IVSUIContext context;
2626
readonly ILocalRepositoryModelFactory repositoryFactory;
27-
readonly object refreshLock = new object();
2827

2928
IGitExt gitService;
3029
IReadOnlyList<ILocalRepositoryModel> activeRepositories;
@@ -41,23 +40,24 @@ public VSGitExt(IGitHubServiceProvider serviceProvider, IVSUIContextFactory fact
4140
this.repositoryFactory = repositoryFactory;
4241

4342
// The IGitExt service isn't available when a TFS based solution is opened directly.
44-
// It will become available when moving to a Git based solution (cause a UIContext event to fire).
43+
// It will become available when moving to a Git based solution (and cause a UIContext event to fire).
4544
context = factory.GetUIContext(new Guid(Guids.GitSccProviderId));
4645

4746
// Start with empty array until we have a change to initialize.
4847
ActiveRepositories = Array.Empty<ILocalRepositoryModel>();
4948

49+
InitializeTask = Task.CompletedTask;
50+
5051
if (context.IsActive && TryInitialize())
5152
{
5253
// Refresh ActiveRepositories on background thread so we don't delay startup.
53-
InitializeTask = Task.Run(() => RefreshActiveRepositories());
54+
QueueRefreshActiveRepositories();
5455
}
5556
else
5657
{
5758
// If we're not in the UIContext or TryInitialize fails, have another go when the UIContext changes.
5859
context.UIContextChanged += ContextChanged;
5960
log.Debug("VSGitExt will be initialized later");
60-
InitializeTask = Task.CompletedTask;
6161
}
6262
}
6363

@@ -68,7 +68,7 @@ void ContextChanged(object sender, VSUIContextChangedEventArgs e)
6868
if (e.Activated && TryInitialize())
6969
{
7070
// Refresh ActiveRepositories on background thread so we don't delay UI context change.
71-
InitializeTask = Task.Run(() => RefreshActiveRepositories());
71+
QueueRefreshActiveRepositories();
7272
context.UIContextChanged -= ContextChanged;
7373
log.Debug("Initialized VSGitExt on UIContextChanged");
7474
}
@@ -83,7 +83,7 @@ bool TryInitialize()
8383
{
8484
if (e.PropertyName == nameof(gitService.ActiveRepositories))
8585
{
86-
RefreshActiveRepositories();
86+
QueueRefreshActiveRepositories();
8787
}
8888
};
8989

@@ -95,19 +95,22 @@ bool TryInitialize()
9595
return false;
9696
}
9797

98+
void QueueRefreshActiveRepositories()
99+
{
100+
// Execute tasks in sequence on thread pool.
101+
InitializeTask = InitializeTask.ContinueWith(_ => RefreshActiveRepositories(), TaskScheduler.Default);
102+
}
103+
98104
void RefreshActiveRepositories()
99105
{
100106
try
101107
{
102-
lock (refreshLock)
103-
{
104-
log.Debug(
105-
"IGitExt.ActiveRepositories (#{Id}) returned {Repositories}",
106-
gitService.GetHashCode(),
107-
gitService?.ActiveRepositories.Select(x => x.RepositoryPath));
108+
log.Debug(
109+
"IGitExt.ActiveRepositories (#{Id}) returned {Repositories}",
110+
gitService.GetHashCode(),
111+
gitService?.ActiveRepositories.Select(x => x.RepositoryPath));
108112

109-
ActiveRepositories = gitService?.ActiveRepositories.Select(x => repositoryFactory.Create(x.RepositoryPath)).ToList();
110-
}
113+
ActiveRepositories = gitService?.ActiveRepositories.Select(x => repositoryFactory.Create(x.RepositoryPath)).ToList();
111114
}
112115
catch (Exception e)
113116
{

test/UnitTests/GitHub.TeamFoundation/VSGitExtTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public void ActiveRepositories_ReadUsingThreadPoolThread()
6363
public class TheActiveRepositoriesChangedEvent
6464
{
6565
[Test]
66-
public void GitExtPropertyChangedEvent_ActiveRepositoriesChangedIsFired()
66+
public async Task GitExtPropertyChangedEvent_ActiveRepositoriesChangedIsFired()
6767
{
6868
var context = CreateVSUIContext(true);
6969
var gitExt = CreateGitExt();
@@ -75,6 +75,7 @@ public void GitExtPropertyChangedEvent_ActiveRepositoriesChangedIsFired()
7575
var eventArgs = new PropertyChangedEventArgs(nameof(gitExt.ActiveRepositories));
7676
gitExt.PropertyChanged += Raise.Event<PropertyChangedEventHandler>(gitExt, eventArgs);
7777

78+
await target.InitializeTask;
7879
Assert.That(wasFired, Is.True);
7980
}
8081

@@ -188,6 +189,7 @@ public async Task ActiveRepositoriesChangedOrderingShouldBeCorrectAcrossThreads(
188189
var task2 = Task.Run(() => gitExt.ActiveRepositories = activeRepositories2);
189190

190191
await Task.WhenAll(task1, task2);
192+
await target.InitializeTask;
191193

192194
Assert.That(target.ActiveRepositories.Single().LocalPath, Is.EqualTo("repo2"));
193195
}

0 commit comments

Comments
 (0)