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

Commit ddf384b

Browse files
committed
Avoid overlapping writes to metrics.json
Guard WriteAllTextAsync using a SemaphoreSlim.
1 parent 12a81c6 commit ddf384b

File tree

1 file changed

+16
-6
lines changed

1 file changed

+16
-6
lines changed

src/GitHub.VisualStudio/Services/UsageService.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.ComponentModel.Composition;
4-
using System.Globalization;
54
using System.IO;
65
using System.Text;
76
using System.Threading;
@@ -25,6 +24,7 @@ public class UsageService : IUsageService
2524

2625
readonly IGitHubServiceProvider serviceProvider;
2726
readonly IEnvironment environment;
27+
readonly SemaphoreSlim writeSemaphoreSlim = new SemaphoreSlim(1, 1);
2828

2929
string storePath;
3030
string userStorePath;
@@ -102,7 +102,7 @@ public async Task<UsageData> ReadLocalData()
102102
SimpleJson.DeserializeObject<UsageData>(json) :
103103
new UsageData { Reports = new List<UsageModel>() };
104104
}
105-
catch(Exception ex)
105+
catch (Exception ex)
106106
{
107107
log.Error(ex, "Error deserializing usage");
108108
return new UsageData { Reports = new List<UsageModel>() };
@@ -115,11 +115,12 @@ public async Task WriteLocalData(UsageData data)
115115
{
116116
Directory.CreateDirectory(Path.GetDirectoryName(storePath));
117117
var json = SimpleJson.SerializeObject(data);
118+
118119
await WriteAllTextAsync(storePath, json);
119120
}
120121
catch (Exception ex)
121122
{
122-
log.Error(ex,"Failed to write usage data");
123+
log.Error(ex, "Failed to write usage data");
123124
}
124125
}
125126

@@ -149,10 +150,19 @@ async Task<string> ReadAllTextAsync(string path)
149150

150151
async Task WriteAllTextAsync(string path, string text)
151152
{
152-
using (var s = new FileStream(path, FileMode.Create))
153-
using (var w = new StreamWriter(s, Encoding.UTF8))
153+
// Avoid IOException when metrics updated multiple times in quick succession
154+
await writeSemaphoreSlim.WaitAsync();
155+
try
156+
{
157+
using (var s = new FileStream(path, FileMode.Create))
158+
using (var w = new StreamWriter(s, Encoding.UTF8))
159+
{
160+
await w.WriteAsync(text);
161+
}
162+
}
163+
finally
154164
{
155-
await w.WriteAsync(text);
165+
writeSemaphoreSlim.Release();
156166
}
157167
}
158168

0 commit comments

Comments
 (0)