private Task <TResult> ExecuteAsync <TResult>(OperationContext context, Func <IContentMetadataService, Task <TResult> > executeAsync, [CallerMemberName] string caller = null)
            where TResult : ResultBase
        {
            return(context.PerformOperationWithTimeoutAsync(
                       Tracer,
                       context =>
            {
                var attempt = -1;
                return _retryPolicy.ExecuteAsync(async() =>
                {
                    attempt++;

                    var result = await context.PerformOperationAsync(Tracer, async() =>
                    {
                        var client = await _metadataServiceClientFactory.CreateClientAsync(context);
                        return await executeAsync(client);
                    },
                                                                     extraEndMessage: _ => $"Attempt=[{attempt}]",
                                                                     caller: caller,
                                                                     traceErrorsOnly: true);

                    // Because we capture exceptions inside the PerformOperation, we need to make sure that they
                    // get propagated for the retry policy to kick in.
                    if (!result.Succeeded && result.HasException)
                    {
                        throw result.Exception;
                    }

                    return result;
                }, context.Token);
            },
                       caller: caller,
                       traceErrorsOnly: true,
                       timeout: _configuration.OperationTimeout));
        }