/// <summary> /// RenewPeriodic is used to periodically invoke Session.Renew on a session until a CancellationToken is cancelled. /// This is meant to be used in a long running call to ensure a session stays valid until completed. /// </summary> /// <param name="initialTTL">The initital TTL to renew for</param> /// <param name="id">The session ID to renew</param> /// <param name="q">Customized write options</param> /// <param name="ct">The CancellationToken used to stop the session from being renewed (e.g. when the long-running action completes)</param> public Task RenewPeriodic(TimeSpan initialTTL, string id, WriteOptions q, CancellationToken ct) { return(Task.Factory.StartNew(async() => { if (q == null) { throw new ArgumentNullException(nameof(q)); } var waitDuration = (int)(initialTTL.TotalMilliseconds / 2); var lastRenewTime = DateTime.Now; Exception lastException = new SessionExpiredException(string.Format("Session expired: {0}", id)); try { while (!ct.IsCancellationRequested) { if (DateTime.Now.Subtract(lastRenewTime) > initialTTL) { throw lastException; } try { await Task.Delay(waitDuration, ct).ConfigureAwait(false); } catch (OperationCanceledException) { // Ignore OperationCanceledException because it means the wait cancelled in response to a CancellationToken being cancelled. } try { var res = await Renew(id, q).ConfigureAwait(false); initialTTL = res.Response.TTL ?? TimeSpan.Zero; waitDuration = (int)(initialTTL.TotalMilliseconds / 2); lastRenewTime = DateTime.Now; } catch (SessionExpiredException) { throw; } catch (OperationCanceledException) { // Ignore OperationCanceledException/TaskCanceledException since it means the session no longer exists or the task is stopping. } catch (Exception ex) { waitDuration = 1000; lastException = ex; } } } finally { if (ct.IsCancellationRequested) { await _client.Session.Destroy(id).ConfigureAwait(false); } } }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap()); }
/// <summary> /// RenewPeriodic is used to periodically invoke Session.Renew on a session until a CancellationToken is cancelled. /// This is meant to be used in a long running call to ensure a session stays valid until completed. /// </summary> /// <param name="initialTTL">The initital TTL to renew for</param> /// <param name="id">The session ID to renew</param> /// <param name="q">Customized write options</param> /// <param name="ct">The CancellationToken used to stop the session from being renewed (e.g. when the long-running action completes)</param> public Task RenewPeriodic(TimeSpan initialTTL, string id, WriteOptions q, CancellationToken ct) { return(Task.Factory.StartNew(async() => { if (q == null) { throw new ArgumentNullException(nameof(q)); } var waitDuration = TimeSpan.FromMilliseconds(initialTTL.TotalMilliseconds / 2); var sw = Stopwatch.StartNew(); var ttl = initialTTL; Exception lastException = new SessionExpiredException(string.Format("Session expired: {0}", id)); try { while (!ct.IsCancellationRequested) { if (sw.Elapsed > ttl) { throw lastException; } try { await Task.Delay(waitDuration, ct).ConfigureAwait(false); var res = await Renew(id, q).ConfigureAwait(false); // Handle the server updating the TTL ttl = res.Response.TTL ?? TimeSpan.Zero; waitDuration = TimeSpan.FromMilliseconds(ttl.TotalMilliseconds / 2); sw = Stopwatch.StartNew(); } catch (SessionExpiredException) { throw; } catch (OperationCanceledException) { // Ignore OperationCanceledException/TaskCanceledException since it means the session no longer exists or the task is stopping. } catch (Exception ex) { waitDuration = TimeSpan.FromSeconds(1); lastException = ex; } } } finally { if (ct.IsCancellationRequested) { await _client.Session.Destroy(id).ConfigureAwait(false); } } }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap()); }