-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Make it easier to add new usage metrics. #1130
Conversation
- Separated IO and date/time comparisons into a separate `UsageService` to allow for easier unit testing - Added some unit tests.
Instead of having a separate method for each usage metric, use a generialized method that takes an expression describing the metric to increment.
9291c30
to
91d86ab
Compare
Conflicts: src/GitHub.App/Models/RepositoryHost.cs src/GitHub.VisualStudio/source.extension.vsixmanifest src/MsiInstaller/Version.wxi src/common/SolutionInfo.cs
|
||
async Task WriteAllTextAsync(string path, string text) | ||
{ | ||
using (var s = File.OpenWrite(path)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be creating a new file, not overwriting the old one.
We need to truncate if file already exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got a few questions and comments. Didn't go through all of it, so there might be more(tm) 😄
WRT splitting out IO so we can unit test, Rothko provides services just for that, fyi
@@ -11,6 +11,7 @@ | |||
<NuGetPackageImportStamp> | |||
</NuGetPackageImportStamp> | |||
<TargetFrameworkProfile /> | |||
<ApplicationVersion>2.3.1.0</ApplicationVersion> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change shouldn't be in here. Bad merge somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, bad merge - well spotted!
|
||
async Task<string> ReadAllTextAsync(string path) | ||
{ | ||
using (var s = File.OpenRead(path)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use rothko for IO services that can be mocked for unit testing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already thought of that, but Rothko doesn't have the methods we need as far as I can tell, which is partly why I split this I/O functionality out into a separate service apart from the usage tracker itself.
async Task TimerTick() | ||
{ | ||
await Initialize(); | ||
|
||
if (firstRun) | ||
if (firstTick) | ||
{ | ||
await IncrementLaunchCount(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IncrementLaunchCount
calls LoadUsage
which calls await Initialize
which has already been called right before this. Do we need these double await Initialize
calls?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, yes we can remove the Initialize
at the top of TimerTick
! 👍
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), | ||
program.ApplicationName, | ||
StoreFileName); | ||
initialized = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a possibility of a race condition here where await Initialize
gets called at the same time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a small possibility, if a counter is initialized on a background thread and while switching to the main thread, another counter is initialized. However all that would happen in that scenario is that services would get loaded twice, which I didn't think was a big enough problem to warrant putting a SemaphoreSlim
or similar around.
The first tick will call `IncrementLaunchCount` which will call `LoadUsage` which will call `Initialize` for us.
@shana any chance of another review of this? I seem to remember you expressing surprise that this hadn't already gone in a few weeks back. |
Currently, adding a new usage metric is a bit of a PITA. You need to:
UsageModel
IUsageTracker
UsageTrackerDispatcher
UsageTracker
UsageTracker.ClearCounters
UsageModel.Clone
This PR:
IncrementX
methods fromIUsageTracker
and replaces them with anIncrementCounter
method which takes a lambda describing the metric to update.UsageTracker.ClearCounters
UsageModel.Clone
UsageTracker
so it can be unit testedUsageTracker