Give file system recording serialization a timeout. (#15217)

Some file I/O is piped from OS processes and never completes,
so without havign a timeout on the recording serialzation, we
end up waiting forever on that I/O to complete.
This commit is contained in:
Todd Volkert 2018-03-07 11:39:59 -08:00 committed by GitHub
parent f3c806c9f2
commit fffb7630c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 12 additions and 6 deletions

View file

@ -7,7 +7,6 @@ import 'package:file/local.dart';
import 'package:file/memory.dart';
import 'package:file/record_replay.dart';
import 'common.dart' show throwToolExit;
import 'context.dart';
import 'platform.dart';
@ -40,7 +39,9 @@ void enableRecordingFileSystem(String location) {
final RecordingFileSystem fileSystem = new RecordingFileSystem(
delegate: _kLocalFs, destination: dir);
addShutdownHook(() async {
await fileSystem.recording.flush();
await fileSystem.recording.flush(
pendingResultTimeout: const Duration(seconds: 5),
);
context.setVariable(FileSystem, originalFileSystem);
}, ShutdownStage.SERIALIZE_RECORDING);
context.setVariable(FileSystem, fileSystem);

View file

@ -26,10 +26,10 @@ typedef Future<dynamic> ShutdownHook();
/// a given stage will be started in parallel and will be guaranteed to run to
/// completion before shutdown hooks in the next stage are started.
class ShutdownStage implements Comparable<ShutdownStage> {
const ShutdownStage._(this._priority);
const ShutdownStage._(this.priority);
/// The stage priority. Smaller values will be run before larger values.
final int _priority;
final int priority;
/// The stage before the invocation recording (if one exists) is serialized
/// to disk. Tasks performed during this stage *will* be recorded.
@ -48,7 +48,7 @@ class ShutdownStage implements Comparable<ShutdownStage> {
static const ShutdownStage CLEANUP = const ShutdownStage._(4);
@override
int compareTo(ShutdownStage other) => _priority.compareTo(other._priority);
int compareTo(ShutdownStage other) => priority.compareTo(other.priority);
}
Map<ShutdownStage, List<ShutdownHook>> _shutdownHooks = <ShutdownStage, List<ShutdownHook>>{};
@ -75,9 +75,11 @@ void addShutdownHook(
/// guaranteed to run to completion before shutdown hooks in the next stage are
/// started.
Future<Null> runShutdownHooks() async {
printTrace('Running shutdown hooks');
_shutdownHooksRunning = true;
try {
for (ShutdownStage stage in _shutdownHooks.keys.toList()..sort()) {
printTrace('Shutdown hook priority ${stage.priority}');
final List<ShutdownHook> hooks = _shutdownHooks.remove(stage);
final List<Future<dynamic>> futures = <Future<dynamic>>[];
for (ShutdownHook shutdownHook in hooks)
@ -88,6 +90,7 @@ Future<Null> runShutdownHooks() async {
_shutdownHooksRunning = false;
}
assert(_shutdownHooks.isEmpty);
printTrace('Shutdown hooks complete');
}
Map<String, String> _environment(bool allowReentrantFlutter, [Map<String, String> environment]) {

View file

@ -5,9 +5,11 @@
import 'package:flutter_tools/src/base/process.dart';
import 'package:test/test.dart';
import '../src/context.dart';
void main() {
group('shutdownHooks', () {
test('runInExpectedOrder', () async {
testUsingContext('runInExpectedOrder', () async {
int i = 1;
int serializeRecording1;
int serializeRecording2;