Commit 6529d91b0f49707a695f977bfbbceb814b6acd90

Authored by 权海
1 parent 7321fbce

feat(ui):让计算结果的上传不要阻塞后续计算

... ... @@ -784,7 +784,6 @@ class TodayController extends GetMaterialController {
checkHealthDataAuthCardVisible(shouldCaculateAndUpload: true);
checkNotificationAuthorizationBannerVisible();
_performHealthDataUpload();
// _startCoreCaculate();
// unawaited(loadDataForDate(selectedDate.value));
}
}
... ...
... ... @@ -355,24 +355,26 @@ class HealthRawDataCoreService {
),
);
await _localStore.upsertResult(newResult);
if (_uploadResultsAfterCalculation) {
await _uploadHrvResults();
await _uploadRealtimeStressResults();
}
_scheduleResultUpload('upload hrv results', _uploadHrvResults);
_scheduleResultUpload(
'upload realtime stress results',
_uploadRealtimeStressResults,
);
final dailyStressPoints = await _calculateAndStoreDailyStressPoints(
userId: userId,
realtimePoints: newResult.realtimeStressPoints,
nowSeconds: effectiveEndTime,
);
_scheduleResultUpload(
'upload daily stress results',
_uploadDailyStressResults,
);
final sleepResults = await _calculateAndStoreSleepResults(
userId: userId,
sleepIntervals: sleepIntervals,
latestSleepResultTime: latestSleepResultTime,
);
if (_uploadResultsAfterCalculation) {
await _uploadDailyStressResults();
await _uploadSleepResults();
}
_scheduleResultUpload('upload sleep results', _uploadSleepResults);
final storedResult = newResult.copyWith(
dailyStressPoints: dailyStressPoints,
sleepResults: sleepResults,
... ... @@ -622,6 +624,24 @@ class HealthRawDataCoreService {
);
}
void _scheduleResultUpload(
String action,
Future<void> Function() upload,
) {
if (!_uploadResultsAfterCalculation) {
return;
}
unawaited(
(() async {
try {
await upload();
} catch (error, stackTrace) {
_logError('$action failed', error, stackTrace);
}
})(),
);
}
Future<void> _uploadHrvResults() async {
if (_isUploadingHrvResults) {
return;
... ...
import 'dart:async';
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/core/services/health_raw_data_core_service.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_local_data_convert.dart';
... ... @@ -7,6 +9,12 @@ import 'package:doublefeel_flutter/pigeon/health_kit_api.g.dart';
import 'package:doublefeel_flutter/pigeon/health_kit_raw_data_api.g.dart';
import 'package:flutter_test/flutter_test.dart';
Future<void> _pumpAsyncUploads() async {
for (var i = 0; i < 6; i += 1) {
await Future<void>.delayed(Duration.zero);
}
}
void main() {
test('sync reads raw data, calculates, stores, and resumes with context',
() async {
... ... @@ -330,6 +338,7 @@ void main() {
endTime: startSeconds + 240,
readChunkDays: 1,
);
await _pumpAsyncUploads();
expect(
operationLog.indexOf('upsertDailyStressPoints'),
... ... @@ -508,6 +517,7 @@ void main() {
)),
readChunkDays: 1,
);
await _pumpAsyncUploads();
final rows = await store.debugQueryAllRows(42);
expect(api.sleepUploadCallCount, 1);
... ... @@ -570,6 +580,7 @@ void main() {
endTime: base + 40,
readChunkDays: 1,
);
await _pumpAsyncUploads();
final rows = await store.debugQueryAllRows(42);
expect(result.hrvStressPoints, isEmpty);
... ... @@ -585,6 +596,52 @@ void main() {
expect(rows.sleepRows.single['uploaded'], 1);
});
test('startCoreCaculate does not wait for pending uploads', () async {
const base = 1800000000;
final api = _FakeHealthKitRawDataHostApi()
..hrvUploadCompleter = Completer<int>()
..hrUploadCompleter = Completer<int>();
final store = _MemoryHealthRawStressLocalStore();
await store.upsertResult(
HealthRawStressCalculationResult(
userId: 42,
hrvStressPoints: [_hrvStressPoint(base + 10)],
realtimeStressPoints: [_realtimeStressPoint(base + 20)],
dailyStressPoints: const <HealthRawDailyStressPoint>[],
),
);
final service = HealthRawDataCoreService(
healthApi: _FakeHealthKitHostApi(),
rawDataApi: api,
localStore: store,
userIdProvider: () => 42,
);
final calculation = service.startCoreCaculate(
endTime: base + 40,
readChunkDays: 1,
);
await _pumpAsyncUploads();
await expectLater(
calculation.timeout(const Duration(seconds: 1)),
completes,
);
expect(api.hrvUploadCallCount, 1);
expect(api.hrUploadCallCount, 1);
var rows = await store.debugQueryAllRows(42);
expect(rows.hrvRows.single['uploaded'], 0);
expect(rows.realtimeRows.single['uploaded'], 0);
api.hrvUploadCompleter!.complete(base + 10);
api.hrUploadCompleter!.complete(base + 20);
await _pumpAsyncUploads();
rows = await store.debugQueryAllRows(42);
expect(rows.hrvRows.single['uploaded'], 1);
expect(rows.realtimeRows.single['uploaded'], 1);
});
test('local data source returns earliest local hr start time', () async {
const base = 1800000000;
final api = _FakeHealthKitRawDataHostApi();
... ... @@ -678,6 +735,8 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
var hrvUploadUntil = 0;
var dailyStressUploadUntil = 0;
var sleepUploadUntil = 0;
Completer<int>? hrUploadCompleter;
Completer<int>? hrvUploadCompleter;
var hasData = true;
void setPoints(int dataType, List<HealthKitRawDataPoint> points) {
... ... @@ -718,12 +777,20 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
@override
Future<int> performHRDataUpload({required String sqliteFilePath}) async {
hrUploadCallCount += 1;
final completer = hrUploadCompleter;
if (completer != null) {
return completer.future;
}
return hrUploadUntil;
}
@override
Future<int> performHRVDataUpload({required String sqliteFilePath}) async {
hrvUploadCallCount += 1;
final completer = hrvUploadCompleter;
if (completer != null) {
return completer.future;
}
return hrvUploadUntil;
}
... ...