stop method
Closes every endpoint, optionally letting in-flight calls finish first.
With drainTimeout null every endpoint closes at once and a running call
fails with UNAVAILABLE. With a budget the endpoints stop admitting new
calls, and their running ones get up to the budget to finish.
Implementation
Future<void> stop({Duration? drainTimeout}) async {
if (drainTimeout != null) {
for (final endpoint in _live.keys) {
// markDraining, not drain(): the latter cancels every active context,
// the opposite of letting in-flight calls finish.
endpoint.markDraining();
}
await drainUntilIdle(
pending: () => inFlightResponderCalls(_live.keys),
budget: drainTimeout,
logger: _log,
);
}
// Concurrently: each close may wait on its own peer, and one dead
// connection must not delay the rest. Caught per endpoint, because
// Future.wait abandons the remaining futures on the first error.
await Future.wait([
for (final endpoint in List.of(_live.keys))
endpoint.close().catchError((Object e) {
_log.warning('Error closing an endpoint: $e');
}),
]);
for (final endpoint in List.of(_live.keys)) {
release(endpoint);
}
}