Ejemplo n.º 1
0
    protected override async ValueTask <IComputed <T> > Compute(
        ComputeMethodInput input, IComputed <T>?existing,
        CancellationToken cancellationToken)
    {
        var version  = VersionGenerator.NextVersion(existing?.Version ?? default);
        var computed = CreateComputed(input, version);

        try {
            using var _ = Computed.ChangeCurrent(computed);
            var result = input.InvokeOriginalFunction(cancellationToken);
            if (input.Method.ReturnsValueTask)
            {
                var output = await((ValueTask <T>)result).ConfigureAwait(false);
                computed.TrySetOutput(output);
            }
            else
            {
                var output = await((Task <T>)result).ConfigureAwait(false);
                computed.TrySetOutput(output);
            }
        }
        catch (OperationCanceledException e) {
            computed.TrySetOutput(Result.Error <T>(e));
            computed.Invalidate();
            throw;
        }
        catch (Exception e) {
            if (e is AggregateException ae)
            {
                e = ae.GetFirstInnerException();
            }
            computed.TrySetOutput(Result.Error <T>(e));
            // Weird case: if the output is already set, all we can
            // is to ignore the exception we've just caught;
            // throwing it further will probably make it just worse,
            // since the the caller have to take this scenario into acc.
        }
        return(computed);
    }
Ejemplo n.º 2
0
    protected override async ValueTask <IComputed <T> > Compute(
        ComputeMethodInput input, IComputed <T>?existing,
        CancellationToken cancellationToken)
    {
        var                       method = input.Method;
        IReplica <T>              replica;
        IReplicaComputed <T>      replicaComputed;
        ReplicaMethodComputed <T> result;

        // 1. Trying to update the Replica first
        if (existing is IReplicaMethodComputed <T> rsc && rsc.Replica != null)
        {
            try {
                replica         = rsc.Replica;
                replicaComputed = (IReplicaComputed <T>)
                                  await replica.Computed.Update(cancellationToken).ConfigureAwait(false);

                result = new (method.Options, input, replicaComputed);
                ComputeContext.Current.TryCapture(result);
                return(result);
            }
            catch (OperationCanceledException) {
                throw;
            }
            catch (Exception e) {
                DebugLog?.LogError(e, "ComputeAsync: error on Replica update");
            }
        }

        // 2. Replica update failed, let's refresh it
        Result <T>           output;
        PublicationStateInfo?psi;

        using (var psiCapture = new PublicationStateInfoCapture()) {
            try {
                var rpcResult = input.InvokeOriginalFunction(cancellationToken);
                if (method.ReturnsValueTask)
                {
                    var task = (ValueTask <T>)rpcResult;
                    output = Result.Value(await task.ConfigureAwait(false));
                }
                else
                {
                    var task = (Task <T>)rpcResult;
                    output = Result.Value(await task.ConfigureAwait(false));
                }
            }
            catch (OperationCanceledException) {
                throw;
            }
            catch (Exception e) {
                DebugLog?.LogError(e, "ComputeAsync: error on update");
                if (e is AggregateException ae)
                {
                    e = ae.GetFirstInnerException();
                }
                output = Result.Error <T>(e);
            }
            psi = psiCapture.Captured;
        }

        if (psi == null)
        {
            output = new Result <T>(default !, Errors.NoPublicationStateInfo());