-
Notifications
You must be signed in to change notification settings - Fork 5
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
EES-5826 - use channels to separate Public API query response from the writing of queries for analytics #5678
base: dev
Are you sure you want to change the base?
Conversation
81d9c6e
to
9307ef6
Compare
…sts for writing queries for analytics, rather than not awaiting the writing process.
9307ef6
to
f2a8898
Compare
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 is very nice!
A few comments but will leave to your discretion. Let me know if you produce anything else for me to review.
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.
Unless you think it provides added clarity, I wouldn't put Channel in the name since that is an implementation detail. You can think if this more as the QueryAnalyticsReporter or Manager or Handler? ie it's just the place where all other components can go to send/report their analytics.
while (!stoppingToken.IsCancellationRequested) | ||
{ | ||
var message = await channel.ReadQuery(stoppingToken); | ||
await queryAnalyticsWriter.ReportDataSetVersionQuery(message); |
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.
If this throws, I'm guessing this background service will stop writing the files? Probably want to guard against that - and log errors?
@@ -47,15 +30,15 @@ public async Task ReportDataSetVersionQuery( | |||
|
|||
Directory.CreateDirectory(directory); |
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.
I would catch and log errors here - permissions, disk full, all sorts of things that could go wrong.
|
||
public ValueTask<CaptureDataSetVersionQueryRequest> ReadQuery(CancellationToken cancellationToken) | ||
{ | ||
return default; |
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.
Could this potentially lead to a spinning process? If something was consuming it, it would be pouring out a stream of values? Perhaps add :
await Task.Delay(Timeout.Infinite, cancellationToken);
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.
Not something for you to change - but just whilst I have your attention :-)
It would be usual for a there to be two interfaces, one as the "Reporter" where components can send their data, and another as a "Consumer" that would take the data out and process it. This cleans up the intentions of components and prevents any possibility of anything else reading from the channel when they should only ever be writing. The container of course resolves to the same instance.
IQueryAnalyticsWriter queryAnalyticsWriter | ||
) : BackgroundService | ||
{ | ||
protected override async Task ExecuteAsync(CancellationToken stoppingToken) |
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.
Can this be unit tested?
|
||
namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Services; | ||
|
||
public class QueryAnalyticsChannel : IQueryAnalyticsChannel |
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.
Unit tests for this class?
This PR:
Rather than spawning off a separate Task from the main request-processing Thread and simply not awaiting it, instead we provide a Channel whereby the DataSetQueryService can write the desired query to be captured to the channel.
A BackgroundService continually monitors the Channel, and reads from the Channel when new messages are available. It then forwards the message to the QueryAnalyticsWriter service, which then performs the actual work of writing out the query for analytics.