in src/CosmosCache.cs [189:273]
public async Task RefreshAsync(string key, CancellationToken token = default(CancellationToken))
{
token.ThrowIfCancellationRequested();
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException(nameof(key));
}
await this.ConnectAsync(token).ConfigureAwait(false);
ItemResponse<CosmosCacheSession> cosmosCacheSessionResponse;
try
{
cosmosCacheSessionResponse = await this.cosmosContainer.ReadItemAsync<CosmosCacheSession>(
partitionKey: new PartitionKey(key),
id: key,
requestOptions: null,
cancellationToken: token).ConfigureAwait(false);
this.options.DiagnosticsHandler?.Invoke(cosmosCacheSessionResponse.Diagnostics);
}
catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
this.options.DiagnosticsHandler?.Invoke(ex.Diagnostics);
return;
}
if (cosmosCacheSessionResponse.Resource.IsSlidingExpiration.GetValueOrDefault())
{
try
{
if (cosmosCacheSessionResponse.Resource.AbsoluteSlidingExpiration.GetValueOrDefault() > 0)
{
long ttl = cosmosCacheSessionResponse.Resource.TimeToLive.Value;
DateTimeOffset absoluteExpiration = DateTimeOffset.FromUnixTimeSeconds(cosmosCacheSessionResponse.Resource.AbsoluteSlidingExpiration.GetValueOrDefault());
if (absoluteExpiration < DateTimeOffset.UtcNow)
{
// At this point the cache item we just read expired, in which case, we should treat it as not found.
// The TTL will clean it up on the container.
return;
}
else
{
double pendingSeconds = (absoluteExpiration - DateTimeOffset.UtcNow).TotalSeconds;
if (pendingSeconds < 1)
{
// Cosmos DB TTL works on seconds granularity and this item has less than a second to live.
// Treat it as a cache-miss.
return;
}
if (pendingSeconds < ttl)
{
cosmosCacheSessionResponse.Resource.TimeToLive = (long)pendingSeconds;
}
}
}
cosmosCacheSessionResponse.Resource.PartitionKeyAttribute = this.options.ContainerPartitionKeyAttribute;
ItemResponse<CosmosCacheSession> replaceCacheSessionResponse = await this.cosmosContainer.ReplaceItemAsync(
partitionKey: new PartitionKey(key),
id: key,
item: cosmosCacheSessionResponse.Resource,
requestOptions: new ItemRequestOptions()
{
IfMatchEtag = cosmosCacheSessionResponse.ETag,
EnableContentResponseOnWrite = false,
},
cancellationToken: token).ConfigureAwait(false);
this.options.DiagnosticsHandler?.Invoke(replaceCacheSessionResponse.Diagnostics);
}
catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
// The cache item has expired in-between the read and replace operations.
this.options.DiagnosticsHandler?.Invoke(ex.Diagnostics);
}
catch (CosmosException cosmosException) when (cosmosException.StatusCode == HttpStatusCode.PreconditionFailed)
{
// Race condition on replace, we need do not need to refresh it
this.options.DiagnosticsHandler?.Invoke(cosmosException.Diagnostics);
}
}
}