static CancellationToken GetCombinedCancellationToken(ref CancellationTokenSource?combinedCts, NpgsqlTimeout timeout, CancellationToken cancellationToken) { var finalCt = cancellationToken; if (timeout.IsSet) { combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); combinedCts.CancelAfter((int)timeout.CheckAndGetTimeLeft().TotalMilliseconds); finalCt = combinedCts.Token; } return(finalCt); }
/// <summary> /// Utility that simplifies awaiting a task with a timeout. If the given task does not /// complete within <paramref name="timeout"/>, a <see cref="TimeoutException"/> is thrown. /// </summary> /// <param name="task">The task to be awaited</param> /// <param name="timeout">How much time to allow <paramref name="task"/> to complete before throwing a <see cref="TimeoutException"/></param> /// <returns>An awaitable task that represents the original task plus the timeout</returns> internal static async Task <T> WithTimeout <T>(this Task <T> task, NpgsqlTimeout timeout) { if (!timeout.IsSet) { return(await task); } var timeLeft = timeout.CheckAndGetTimeLeft(); if (task != await Task.WhenAny(task, Task.Delay(timeLeft))) { throw new TimeoutException(); } return(await task); }
/// <summary> /// Called exactly once per multiplexing pool, when the first connection is opened, with two goals: /// 1. Load types and bind the pool-wide type mapper (necessary for binding parameters) /// 2. Cause any connection exceptions (e.g. bad username) to be thrown from NpgsqlConnection.Open /// </summary> internal async Task BootstrapMultiplexing(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken = default) { Debug.Assert(_multiplexing); var hasSemaphore = async ? await _bootstrapSemaphore !.WaitAsync(timeout.CheckAndGetTimeLeft(), cancellationToken) : _bootstrapSemaphore !.Wait(timeout.CheckAndGetTimeLeft(), cancellationToken); // We've timed out - calling Check, to throw the correct exception if (!hasSemaphore) { timeout.Check(); } try { if (IsBootstrapped) { return; } var connector = await conn.StartBindingScope(ConnectorBindingScope.Connection, timeout, async, cancellationToken); using var _ = Defer(static conn => conn.EndBindingScope(ConnectorBindingScope.Connection), conn);