private void SetBatchResults( IDictionary <TKey, TaskCompletionSource <TValue> > bufferedPromises, IReadOnlyList <TKey> resolvedKeys, IReadOnlyList <IResult <TValue> > results) { if (resolvedKeys.Count == results.Count) { for (var i = 0; i < resolvedKeys.Count; i++) { SetSingleResult(bufferedPromises[resolvedKeys[i]], resolvedKeys[i], results[i]); } } else { Exception error = Errors.CreateKeysAndValuesMustMatch( resolvedKeys.Count, results.Count); for (var i = 0; i < resolvedKeys.Count; i++) { DispatchingDiagnostics.RecordError(resolvedKeys[i], error); bufferedPromises[resolvedKeys[i]].SetException(error); } } }
private async Task DispatchAsync( TKey resolvedKey, TaskCompletionSource <TValue> promise) { var resolvedKeys = new TKey[] { resolvedKey }; Activity activity = DispatchingDiagnostics .StartBatching(resolvedKeys); IReadOnlyList <IResult <TValue> > results = await Fetch(resolvedKeys).ConfigureAwait(false); if (results.Count == 1) { SetSingleResult(promise, resolvedKey, results.First()); } else { Exception error = Errors.CreateKeysAndValuesMustMatch(1, results.Count); DispatchingDiagnostics.RecordError(resolvedKey, error); promise.SetException(error); } DispatchingDiagnostics.StopBatching(activity, resolvedKeys, results); }
private async Task FetchInternalAsync( IDictionary <TKey, TaskCompletionSource <TValue> > bufferedPromises, IReadOnlyList <TKey> resolvedKeys) { Activity activity = DispatchingDiagnostics .StartBatching(resolvedKeys); IReadOnlyList <IResult <TValue> > results = await Fetch(resolvedKeys).ConfigureAwait(false); SetBatchResults(bufferedPromises, resolvedKeys, results); DispatchingDiagnostics.StopBatching(activity, resolvedKeys, results); }
/// <inheritdoc /> public Task <TValue> LoadAsync(TKey key) { if (key == null) { throw new ArgumentNullException(nameof(key)); } lock (_sync) { TKey resolvedKey = _cacheKeyResolver(key); if (_options.Caching && _cache.TryGetValue(resolvedKey, out Task <TValue> cachedValue)) { DispatchingDiagnostics.RecordCachedValue(resolvedKey, cachedValue); return(cachedValue); } var promise = new TaskCompletionSource <TValue>( TaskCreationOptions.RunContinuationsAsynchronously); if (_options.Batching) { if (!_buffer.TryAdd(resolvedKey, promise) && _buffer.TryGetValue(resolvedKey, out TaskCompletionSource <TValue> value)) { promise.TrySetCanceled(); promise = value; } } else { // note: must run in the background; do not await here. Task.Factory.StartNew( () => DispatchAsync(resolvedKey, promise), TaskCreationOptions.RunContinuationsAsynchronously); } if (_options.Caching) { _cache.TryAdd(resolvedKey, promise.Task); } return(promise.Task); } }
private void SetSingleResult( TaskCompletionSource <TValue> promise, TKey resolvedKey, IResult <TValue> result) { if (result.IsError) { DispatchingDiagnostics.RecordError(resolvedKey, result.Error); promise.SetException(result.Error); } else { promise.SetResult(result.Value); } }