Skip to content

Commit e3dd149

Browse files
authored
Use futures list internally to manage send events (#184)
* Refactor to use internal `_futures` list of sent events * Update tests * Bump major version to 5.0.0 * Provide delay duration when closing http connection * Nit fixes from review * Convert to wip
1 parent 15cc9c7 commit e3dd149

8 files changed

+57
-36
lines changed

pkgs/unified_analytics/CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
## 4.0.2-wip
1+
## 5.0.0-wip
22

3-
- Update to the latest version of `package:dart_flutter_team_lints`.
3+
- Update to the latest version of `package:dart_flutter_team_lints`
4+
- Using internal futures list to store send events
45

56
## 4.0.1
67

pkgs/unified_analytics/example/unified_analytics_example.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ void main() async {
5353
final hotReloadEvent = Event.hotReloadTime(timeMs: runTime);
5454

5555
// Make a call to the [Analytics] api to send the data
56-
await analytics.send(hotReloadEvent);
56+
analytics.send(hotReloadEvent);
5757

5858
// Close the client connection on exit
59-
analytics.close();
59+
await analytics.close();
6060
}

pkgs/unified_analytics/lib/src/analytics.dart

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,13 @@ abstract class Analytics {
225225
///
226226
/// Prevents the tool from hanging when if there are still requests
227227
/// that need to be sent off.
228-
void close();
228+
///
229+
/// Providing [delayDuration] in milliseconds will allow the instance
230+
/// to wait the provided time before closing the http connection. Keeping
231+
/// the connection open for some time will allow any pending events that
232+
/// are waiting to be sent to the Google Analytics server. Default value
233+
/// of 250 ms applied.
234+
Future<void> close({int delayDuration = kDelayDuration});
229235

230236
/// Method to fetch surveys from the endpoint [kContextualSurveyUrl].
231237
///
@@ -248,7 +254,7 @@ abstract class Analytics {
248254
/// ```dart
249255
/// analytics.send(Event.memory(periodSec: 123));
250256
/// ```
251-
Future<Response>? send(Event event);
257+
void send(Event event);
252258

253259
/// Pass a boolean to either enable or disable telemetry and make
254260
/// the necessary changes in the persisted configuration file.
@@ -326,6 +332,10 @@ class AnalyticsImpl implements Analytics {
326332
/// Telemetry suppression flag that is set via [Analytics.suppressTelemetry].
327333
bool _telemetrySuppressed = false;
328334

335+
/// The list of futures that will contain all of the send events
336+
/// from the [GAClient].
337+
final _futures = <Future<Response>>[];
338+
329339
AnalyticsImpl({
330340
required this.tool,
331341
required Directory homeDirectory,
@@ -472,7 +482,13 @@ class AnalyticsImpl implements Analytics {
472482
}
473483

474484
@override
475-
void close() => _gaClient.close();
485+
Future<void> close({int delayDuration = kDelayDuration}) async {
486+
await Future.wait(_futures).timeout(
487+
Duration(milliseconds: delayDuration),
488+
onTimeout: () => [],
489+
);
490+
_gaClient.close();
491+
}
476492

477493
@override
478494
Future<List<Survey>> fetchAvailableSurveys() async {
@@ -543,8 +559,8 @@ class AnalyticsImpl implements Analytics {
543559
LogFileStats? logFileStats() => _logHandler.logFileStats();
544560

545561
@override
546-
Future<Response>? send(Event event) {
547-
if (!okToSend) return null;
562+
void send(Event event) {
563+
if (!okToSend) return;
548564

549565
// Construct the body of the request
550566
final body = generateRequestBody(
@@ -558,8 +574,9 @@ class AnalyticsImpl implements Analytics {
558574

559575
_logHandler.save(data: body);
560576

561-
// Pass to the google analytics client to send
562-
return _gaClient.sendData(body);
577+
final gaClientFuture = _gaClient.sendData(body);
578+
_futures.add(gaClientFuture);
579+
gaClientFuture.whenComplete(() => _futures.remove(gaClientFuture));
563580
}
564581

565582
@override
@@ -670,8 +687,8 @@ class FakeAnalytics extends AnalyticsImpl {
670687
);
671688

672689
@override
673-
Future<Response>? send(Event event) {
674-
if (!okToSend) return null;
690+
void send(Event event) {
691+
if (!okToSend) return;
675692

676693
// Construct the body of the request
677694
final body = generateRequestBody(
@@ -688,7 +705,6 @@ class FakeAnalytics extends AnalyticsImpl {
688705
// Using this list to validate that events are being sent
689706
// for internal methods in the `Analytics` instance
690707
sentEvents.add(event);
691-
return _gaClient.sendData(body);
692708
}
693709
}
694710

@@ -730,7 +746,7 @@ class NoOpAnalytics implements Analytics {
730746
void clientShowedMessage() {}
731747

732748
@override
733-
void close() {}
749+
Future<void> close({int delayDuration = kDelayDuration}) async {}
734750

735751
@override
736752
Future<List<Survey>> fetchAvailableSurveys() async => const <Survey>[];

pkgs/unified_analytics/lib/src/constants.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ const String kContextualSurveyUrl =
5959
/// will be located.
6060
const String kDartToolDirectoryName = '.dart-tool';
6161

62+
/// The default time to wait before closing the http connection to allow for
63+
/// pending events to be sent.
64+
const int kDelayDuration = 250;
65+
6266
/// Name of the file where we persist dismissed survey ids.
6367
const String kDismissedSurveyFileName =
6468
'dart-flutter-telemetry-dismissed-surveys.json';
@@ -78,7 +82,7 @@ const int kLogFileLength = 2500;
7882
const String kLogFileName = 'dart-flutter-telemetry.log';
7983

8084
/// The current version of the package, should be in line with pubspec version.
81-
const String kPackageVersion = '4.0.2-wip';
85+
const String kPackageVersion = '5.0.0-wip';
8286

8387
/// The minimum length for a session.
8488
const int kSessionDurationMinutes = 30;

pkgs/unified_analytics/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: >-
44
to Google Analytics.
55
# When updating this, keep the version consistent with the changelog and the
66
# value in lib/src/constants.dart.
7-
version: 4.0.2-wip
7+
version: 5.0.0-wip
88
repository: https://github.com/dart-lang/tools/tree/main/pkgs/unified_analytics
99

1010
environment:

pkgs/unified_analytics/test/log_handler_test.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void main() {
6565
final countOfEventsToSend = 10;
6666

6767
for (var i = 0; i < countOfEventsToSend; i++) {
68-
await analytics.send(testEvent);
68+
analytics.send(testEvent);
6969
}
7070

7171
expect(analytics.logFileStats(), isNotNull);
@@ -91,7 +91,7 @@ void main() {
9191
final countOfEventsToSend = 10;
9292

9393
for (var i = 0; i < countOfEventsToSend; i++) {
94-
await analytics.send(testEvent);
94+
analytics.send(testEvent);
9595
}
9696
final logFileStats = analytics.logFileStats();
9797

@@ -110,7 +110,7 @@ void main() {
110110
final countOfEventsToSend = 10;
111111

112112
for (var i = 0; i < countOfEventsToSend; i++) {
113-
await analytics.send(testEvent);
113+
analytics.send(testEvent);
114114
}
115115
final logFileStats = analytics.logFileStats();
116116

@@ -149,7 +149,7 @@ void main() {
149149
// one malformed record on top of the logs and the rest
150150
// are valid log records
151151
for (var i = 0; i < kLogFileLength - 1; i++) {
152-
await analytics.send(testEvent);
152+
analytics.send(testEvent);
153153
}
154154
final logFileStats = analytics.logFileStats();
155155
expect(logFile.readAsLinesSync().length, kLogFileLength);
@@ -159,7 +159,7 @@ void main() {
159159
expect(logFile.readAsLinesSync()[0].trim(), '{{');
160160

161161
// Sending one more event should flush out the malformed record
162-
await analytics.send(testEvent);
162+
analytics.send(testEvent);
163163

164164
final secondLogFileStats = analytics.logFileStats();
165165
expect(secondLogFileStats, isNotNull);
@@ -178,7 +178,7 @@ void main() {
178178
// Ensure it will work as expected after writing correct logs
179179
final countOfEventsToSend = 10;
180180
for (var i = 0; i < countOfEventsToSend; i++) {
181-
await analytics.send(testEvent);
181+
analytics.send(testEvent);
182182
}
183183
final secondLogFileStats = analytics.logFileStats();
184184

pkgs/unified_analytics/test/suppression_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ void main() {
7676

7777
test('Suppression works as expected', () async {
7878
analytics.suppressTelemetry();
79-
await analytics.send(testEvent);
79+
analytics.send(testEvent);
8080

8181
final logFileStats = analytics.logFileStats();
8282

@@ -86,7 +86,7 @@ void main() {
8686

8787
test('Second instance is not suppressed', () async {
8888
analytics.suppressTelemetry();
89-
await analytics.send(testEvent);
89+
analytics.send(testEvent);
9090

9191
final logFileStats = analytics.logFileStats();
9292

@@ -110,7 +110,7 @@ void main() {
110110

111111
// Using a new event here to differentiate from the first one
112112
final newEvent = Event.commandExecuted(count: 2, name: 'commandName');
113-
await secondAnalytics.send(newEvent);
113+
secondAnalytics.send(newEvent);
114114

115115
// Both instances of `Analytics` should now have data retrieved
116116
// from `LogFileStats()` even though only the second instance

pkgs/unified_analytics/test/survey_handler_test.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ void main() {
358358

359359
// Simulate 60 events to send so that the first condition is satisified
360360
for (var i = 0; i < 60; i++) {
361-
await analytics.send(testEvent);
361+
analytics.send(testEvent);
362362
}
363363

364364
final fetchedSurveys = await analytics.fetchAvailableSurveys();
@@ -405,7 +405,7 @@ void main() {
405405

406406
// Simulate 60 events to send so that the first condition is satisified
407407
for (var i = 0; i < 60; i++) {
408-
await analytics.send(testEvent);
408+
analytics.send(testEvent);
409409
}
410410

411411
final fetchedSurveys = await analytics.fetchAvailableSurveys();
@@ -448,7 +448,7 @@ void main() {
448448

449449
// Simulate 60 events to send so that the first condition is satisified
450450
for (var i = 0; i < 60; i++) {
451-
await analytics.send(testEvent);
451+
analytics.send(testEvent);
452452
}
453453

454454
await analytics.setTelemetry(false);
@@ -515,7 +515,7 @@ void main() {
515515

516516
// Simulate 60 events to send so that the first condition is satisified
517517
for (var i = 0; i < 60; i++) {
518-
await analytics.send(testEvent);
518+
analytics.send(testEvent);
519519
}
520520

521521
final fetchedSurveys = await analytics.fetchAvailableSurveys();
@@ -617,7 +617,7 @@ void main() {
617617

618618
// Simulate 60 events to send so that the first condition is satisified
619619
for (var i = 0; i < 60; i++) {
620-
await analytics.send(testEvent);
620+
analytics.send(testEvent);
621621
}
622622

623623
final fetchedSurveys = await analytics.fetchAvailableSurveys();
@@ -686,7 +686,7 @@ void main() {
686686

687687
// Simulate 60 events to send so that the first condition is satisified
688688
for (var i = 0; i < 60; i++) {
689-
await analytics.send(testEvent);
689+
analytics.send(testEvent);
690690
}
691691

692692
final fetchedSurveys = await analytics.fetchAvailableSurveys();
@@ -743,7 +743,7 @@ void main() {
743743

744744
// Simulate 60 events to send so that the first condition is satisified
745745
for (var i = 0; i < 60; i++) {
746-
await analytics.send(testEvent);
746+
analytics.send(testEvent);
747747
}
748748

749749
// Setting to false will prevent anything from getting returned
@@ -758,7 +758,7 @@ void main() {
758758
// at least 50 records for one of the conditions
759759
await analytics.setTelemetry(true);
760760
for (var i = 0; i < 60; i++) {
761-
await analytics.send(testEvent);
761+
analytics.send(testEvent);
762762
}
763763
fetchedSurveys = await analytics.fetchAvailableSurveys();
764764
expect(fetchedSurveys.length, 1);
@@ -805,7 +805,7 @@ void main() {
805805

806806
// Simulate 60 events to send so that the first condition is satisified
807807
for (var i = 0; i < 60; i++) {
808-
await analytics.send(testEvent);
808+
analytics.send(testEvent);
809809
}
810810

811811
final fetchedSurveys = await analytics.fetchAvailableSurveys();
@@ -851,7 +851,7 @@ void main() {
851851

852852
// Simulate 60 events to send so that the first condition is satisified
853853
for (var i = 0; i < 60; i++) {
854-
await analytics.send(testEvent);
854+
analytics.send(testEvent);
855855
}
856856

857857
final fetchedSurveys = await analytics.fetchAvailableSurveys();

0 commit comments

Comments
 (0)