public static async Task IncrementCounter()
        {
            #region Part02_IncrementCounter
            var counters = CreateServices().GetRequiredService <CounterService>();

            Task.Run(async() => {
                for (var i = 0; i <= 5; i++)
                {
                    await Task.Delay(1000);
                    counters.Increment("a");
                }
            }).Ignore();

            var computed = await Computed.Capture(_ => counters.Get("a"));

            WriteLine($"{DateTime.Now}: {computed.Value}");
            for (var i = 0; i < 5; i++)
            {
                await computed.WhenInvalidated();

                computed = await computed.Update(false);

                WriteLine($"{DateTime.Now}: {computed.Value}");
            }
            #endregion
        }
Example #2
0
        public async Task InvalidateEverythingTest()
        {
            var users = Services.GetRequiredService <IUserService>();
            // We need at least 1 user to see count invalidation messages
            await users.Create(new(new User()
            {
                Id = int.MaxValue,
                Name = "Chuck Norris",
            }));

            var u1 = await users.TryGet(int.MaxValue);

            var c1 = await Computed.Capture(_ => users.Count());

            users.Invalidate();

            var u2 = await users.TryGet(int.MaxValue);

            var c2 = await Computed.Capture(_ => users.Count());

            u2.Should().NotBeSameAs(u1);
            u2 !.Id.Should().Be(u1 !.Id);
            u2.Name.Should().Be(u1.Name);

            c2.Should().NotBeSameAs(c1);
            c2 !.Value.Should().Be(c1 !.Value);
        }
Example #3
0
    public async Task AutoRecomputeTest()
    {
        var stateFactory = Services.StateFactory();
        var time         = Services.GetRequiredService <ITimeService>();
        var c            = await Computed.Capture(
            _ => time.GetTimeWithOffset(TimeSpan.FromSeconds(1)));

        var count = 0L;

        using var state = stateFactory.NewComputed <DateTime>(
                  UpdateDelayer.ZeroDelay,
                  async(_, ct) => await c.Use(ct));
        state.Updated += (s, _)
                         => Log.LogInformation($"{++count} -> {s.Value:hh:mm:ss:fff}");

        await TestExt.WhenMet(
            () => count.Should().BeGreaterThan(2),
            TimeSpan.FromSeconds(5));

        var lastCount = count;

        state.Dispose();

        await Task.Delay(1000);

        count.Should().Be(lastCount);
    }
Example #4
0
        private async Task <IComputed <Screenshot> > GetScreenshotComputed()
        {
            var screenshots = Services.GetRequiredService <IScreenshotService>();
            var computed    = await Computed.Capture(_ => screenshots.GetScreenshot(1280));

            return(computed);
        }
Example #5
0
    public static async Task <IPublication <T>?> TryPublish <T>(
        this IPublisher publisher,
        Func <CancellationToken, Task <T> > producer,
        CancellationToken cancellationToken = default)
    {
        var computed = await Computed
                       .Capture(producer, cancellationToken)
                       .ConfigureAwait(false);

        if (computed == null)
        {
            return(null);
        }

        var publication = (IPublication <T>)publisher.Publish(computed);

        // Publication doesn't have to be "in sync" with the computed
        // we requested it for (i.e. it might still point to its older,
        // inconsistent version), so we have to update it here.
        try {
            await publication.Update(cancellationToken).ConfigureAwait(false);
        }
        catch (OperationCanceledException) {
            throw;
        }
        catch {
            // Intended, it's fine to publish a computed w/ an error
        }
        return(publication);
    }
        public async Task BasicTest()
        {
            var kvs = Services.GetRequiredService <IKeyValueStore>();
            var c1  = await Computed.Capture(_ => kvs.TryGet("1"));

            var c2 = await Computed.Capture(_ => kvs.TryGet("2"));

            var c3 = await Computed.Capture(_ => kvs.TryGet("3"));

            c1.Value.Should().BeNull();
            c2.Value.Should().BeNull();
            c3.Value.Should().BeNull();

            var commander = Services.Commander();
            var command   = new NestedOperationLoggerTester.SetManyCommand(
                new[] { "1", "2", "3" }, "v");
            await commander.Call(command);

            c1.IsInvalidated().Should().BeTrue();
            c2.IsInvalidated().Should().BeTrue();
            c3.IsInvalidated().Should().BeTrue();
            c1 = await c1.Update();

            c2 = await c2.Update();

            c3 = await c3.Update();

            c1.Value.Should().Be("v3");
            c2.Value.Should().Be("v2");
            c3.Value.Should().Be("v1");
        }
Example #7
0
    public async Task BasicTest()
    {
        var services    = CreateServiceProviderFor <MathService>();
        var math        = services.GetRequiredService <MathService>();
        var allComputed = new HashSet <IComputed>();

        var c1 = await Computed.Capture(_ => math.Sum(null));

        c1.Value.Should().Be(0);
        allComputed.Add(c1);
        var c2 = await Computed.Capture(_ => math.Sum(null));

        c2.Should().BeSameAs(c1);

        for (var i = 0; i < 20; i++)
        {
            var values = Enumerable.Range(0, i).ToArray();
            c1 = await Computed.Capture(_ => math.Sum(values));

            c1.Value.Should().Be(values.Sum());
            allComputed.Add(c1);
            c2 = await Computed.Capture(_ => math.Sum(values));

            c2.Should().BeSameAs(c1);
        }

        allComputed.Count.Should().Be(21);
    }
Example #8
0
    public async Task BasicTest()
    {
        var time = Services.GetRequiredService <IFusionTime>();

        var cTime = await Computed.Capture(_ => time.GetUtcNow());

        cTime.IsConsistent().Should().BeTrue();
        (DateTime.UtcNow - cTime.Value).Should().BeLessThan(TimeSpan.FromSeconds(1.1));
        await Delay(1.3);

        cTime.IsConsistent().Should().BeFalse();

        cTime = await Computed.Capture(_ => time.GetUtcNow(TimeSpan.FromMilliseconds(200)));

        cTime.IsConsistent().Should().BeTrue();
        await Delay(0.25);

        cTime.IsConsistent().Should().BeFalse();

        var now = DateTime.UtcNow;
        var ago = await time.GetMomentsAgo(now);

        ago.Should().Be("just now");
        await Delay(1.8);

        ago = await time.GetMomentsAgo(now);

        ago.Should().Be("1 second ago");
    }
Example #9
0
        public async Task KeepAliveTimeTest()
        {
            var users = Services.GetRequiredService <IUserService>();

            var cUser0 = await Computed.Capture(_ => users.TryGet(0));

            var cCount = await Computed.Capture(_ => users.Count());

            cUser0 !.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(1));
            cCount !.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(1));
        }
        public static async Task CaptureComputed()
        {
            #region Part02_CaptureComputed
            var counters = CreateServices().GetRequiredService <CounterService>();
            var computed = await Computed.Capture(_ => counters.Get("a"));

            WriteLine($"Computed: {computed}");
            WriteLine($"- IsConsistent(): {computed.IsConsistent()}");
            WriteLine($"- Value:          {computed.Value}");
            #endregion
        }
Example #11
0
    public async Task ExceptionCaptureTest()
    {
        var p = Services.GetRequiredService <ISimplestProvider>();

        p.SetValue(null !); // Will cause an exception in GetCharCount
        var c1Opt = await Computed.TryCapture(_ => p.GetCharCount());

        var c2 = await Computed.Capture(_ => p.GetCharCount());

        c1Opt.Value.Error !.GetType().Should().Be(typeof(NullReferenceException));
        c2.Should().BeSameAs(c1Opt.Value);
    }
Example #12
0
        public static async Task Caching4()
        {
            #region Part05_Caching4
            var service  = CreateServices().GetRequiredService <Service2>();
            var computed = await Computed.Capture(_ => service.Get("a"));

            WriteLine("computed = GetAsync(a) completed");
            WriteLine(await service.Combine("a", "b"));
            GC.Collect();
            WriteLine("GC.Collect() completed");
            WriteLine(await service.Combine("a", "b"));
            #endregion
        }
Example #13
0
    public async Task WatchProduct(string productId, CancellationToken cancellationToken = default)
    {
        var productService = WatchServices.GetRequiredService <IProductService>();
        var computed       = await Computed.Capture(ct => productService.Get(productId, ct), cancellationToken);

        while (true)
        {
            WriteLine($"  {computed.Value}");
            await computed.WhenInvalidated(cancellationToken);

            computed = await computed.Update(cancellationToken);
        }
    }
Example #14
0
    public async Task WatchCartTotal(string cartId, CancellationToken cancellationToken = default)
    {
        var cartService = WatchServices.GetRequiredService <ICartService>();
        var computed    = await Computed.Capture(ct => cartService.GetTotal(cartId, ct), cancellationToken);

        while (true)
        {
            WriteLine($"  {cartId}: total = {computed.Value}");
            await computed.WhenInvalidated(cancellationToken);

            computed = await computed.Update(cancellationToken);
        }
    }
Example #15
0
        public static Task <IComputed <T> > MaybePublish <T>(
            this HttpContext httpContext,
            IPublisher publisher,
            Func <CancellationToken, Task <T> > producer,
            CancellationToken cancellationToken = default)
        {
            var headers     = httpContext.Request.Headers;
            var mustPublish = headers.TryGetValue(FusionHeaders.RequestPublication, out var _);

            return(mustPublish
                ? httpContext.Publish(publisher, producer, cancellationToken)
                : Computed.Capture(producer, cancellationToken));
        }
Example #16
0
        public static async Task Caching2()
        {
            #region Part05_Caching2
            var service  = CreateServices().GetRequiredService <Service1>();
            var computed = await Computed.Capture(_ => service.Get("a"));

            WriteLine(await service.Get("a"));
            WriteLine(await service.Get("a"));
            GC.Collect();
            WriteLine("GC.Collect()");
            WriteLine(await service.Get("a"));
            WriteLine(await service.Get("a"));
            #endregion
        }
        public static async Task InvalidateComputed1()
        {
            #region Part02_InvalidateComputed1
            var counters = CreateServices().GetRequiredService <CounterService>();
            var computed = await Computed.Capture(_ => counters.Get("a"));

            WriteLine($"computed: {computed}");
            WriteLine("computed.Invalidate()");
            computed.Invalidate();
            WriteLine($"computed: {computed}");
            var newComputed = await computed.Update(false);

            WriteLine($"newComputed: {newComputed}");
            #endregion
        }
        public static async Task InvalidateComputed2()
        {
            #region Part02_InvalidateComputed2
            var counters = CreateServices().GetRequiredService <CounterService>();
            var computed = await Computed.Capture(_ => counters.Get("a"));

            WriteLine($"computed: {computed}");
            WriteLine("using (Computed.Invalidate()) counters.GetAsync(\"a\"))");
            using (Computed.Invalidate()) // <- This line
                counters.Get("a").Ignore();
            WriteLine($"computed: {computed}");
            var newComputed = await Computed.Capture(_ => counters.Get("a")); // <- This line

            WriteLine($"newComputed: {newComputed}");
            #endregion
        }
Example #19
0
    public async Task OptionsTest()
    {
        var d = ComputedOptions.Default;
        var p = Services.GetRequiredService <ISimplestProvider>();

        p.SetValue("");

        var c1 = await Computed.Capture(_ => p.GetValue());

        c1.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(10));
        c1.Options.ErrorAutoInvalidateTime.Should().Be(d.ErrorAutoInvalidateTime);
        c1.Options.AutoInvalidateTime.Should().Be(d.AutoInvalidateTime);

        var c2 = await Computed.Capture(_ => p.GetCharCount());

        c2.Options.KeepAliveTime.Should().Be(TimeSpan.FromSeconds(0.5));
        c2.Options.ErrorAutoInvalidateTime.Should().Be(TimeSpan.FromSeconds(0.5));
        c2.Options.AutoInvalidateTime.Should().Be(d.AutoInvalidateTime);
    }
Example #20
0
    public async Task CounterServiceTest()
    {
        using var stopCts = new CancellationTokenSource();
        var cancellationToken = stopCts.Token;

        async Task Watch <T>(string name, IComputed <T> computed)
        {
            while (true)
            {
                Out.WriteLine($"{name}: {computed.Value}, {computed}");
                await computed.WhenInvalidated(cancellationToken);

                Out.WriteLine($"{name}: {computed.Value}, {computed}");
                computed = await computed.Update(cancellationToken);
            }
        }

        var services  = CreateServiceProviderFor <CounterService>();
        var counters  = services.GetRequiredService <CounterService>();
        var aComputed = await Computed.Capture(_ => counters.Get("a"));

        _ = Task.Run(() => Watch(nameof(aComputed), aComputed));
        var bComputed = await Computed.Capture(_ => counters.Get("b"));

        _ = Task.Run(() => Watch(nameof(bComputed), bComputed));

        await counters.Increment("a");

        await counters.SetOffset(10);

        aComputed = await aComputed.Update();

        aComputed.Value.Should().Be(11);
        aComputed.IsConsistent().Should().BeTrue();

        bComputed = await bComputed.Update();

        bComputed.Value.Should().Be(10);
        bComputed.IsConsistent().Should().BeTrue();

        stopCts.Cancel();
    }
Example #21
0
    public async Task BasicTest()
    {
        var services = CreateServiceProviderFor <CounterService>();
        var counters = services.GetRequiredService <CounterService>();

        var c = Computed.GetExisting(() => counters.Get("a"));

        c.Should().BeNull();

        c = await Computed.Capture(_ => counters.Get("a"));

        c.Value.Should().Be(0);
        var c1 = Computed.GetExisting(() => counters.Get("a"));

        c1.Should().BeSameAs(c);

        await counters.Increment("a");

        c.IsConsistent().Should().BeFalse();
        c1 = Computed.GetExisting(() => counters.Get("a"));
        c1.Should().BeNull();
    }
Example #22
0
        public async Task BasicTest()
        {
            using var stopCts = new CancellationTokenSource();
            var cancellationToken = stopCts.Token;

            async Task Watch <T>(string name, IComputed <T> computed)
            {
                for (;;)
                {
                    Out.WriteLine($"{name}: {computed.Value}, {computed}");
                    await computed.WhenInvalidated(cancellationToken);

                    Out.WriteLine($"{name}: {computed.Value}, {computed}");
                    computed = await computed.Update(cancellationToken);
                }
            }

            var services       = CreateServiceProviderFor <PerUserCounterService>();
            var counters       = services.GetRequiredService <PerUserCounterService>();
            var sessionFactory = services.GetRequiredService <ISessionFactory>();
            var sessionA       = sessionFactory.CreateSession();
            var sessionB       = sessionFactory.CreateSession();

            var session    = sessionA;
            var aaComputed = await Computed.Capture(_ => counters.Get("a", session));

            Task.Run(() => Watch(nameof(aaComputed), aaComputed)).Ignore();
            var abComputed = await Computed.Capture(_ => counters.Get("b", session));

            Task.Run(() => Watch(nameof(abComputed), abComputed)).Ignore();

            session = sessionB;
            var baComputed = await Computed.Capture(_ => counters.Get("a", session));

            Task.Run(() => Watch(nameof(baComputed), baComputed)).Ignore();

            session = sessionA;
            await counters.Increment("a", session);

            (await aaComputed.Update()).Value.Should().Be(1);
            (await abComputed.Update()).Value.Should().Be(0);
            (await baComputed.Update()).Value.Should().Be(0);
            await counters.Increment("b", session);

            (await aaComputed.Update()).Value.Should().Be(1);
            (await abComputed.Update()).Value.Should().Be(1);
            (await baComputed.Update()).Value.Should().Be(0);

            session = sessionB;
            await counters.Increment("a", session);

            (await aaComputed.Update()).Value.Should().Be(1);
            (await abComputed.Update()).Value.Should().Be(1);
            (await baComputed.Update()).Value.Should().Be(1);
            await counters.Increment("b", session);

            (await aaComputed.Update()).Value.Should().Be(1);
            (await abComputed.Update()).Value.Should().Be(1);
            (await baComputed.Update()).Value.Should().Be(1);

            stopCts.Cancel();
        }
        private async Task ActualTest(IEdgeCaseService service)
        {
            var error = (Exception?)null;
            await service.SetSuffix("");

            (await service.GetSuffix()).Should().Be("");

            // ThrowIfContainsErrorAsync method test
            var c1 = await Computed.Capture(
                ct => service.ThrowIfContainsError("a", ct));

            c1.Value.Should().Be("a");

            var c2 = await Computed.Capture(
                ct => service.ThrowIfContainsError("error", ct));

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorExceptionType);
            c2.Error.Message.Should().Be("!");

            await service.SetSuffix("z");

            c1 = await Update(c1);

            c1.Value.Should().Be("az");

            c2 = await Update(c2);

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorExceptionType);
            c2.Error.Message.Should().Be("!");
            await service.SetSuffix("");

            // ThrowIfContainsErrorRewriteErrorsAsync method test
            c1 = await Computed.Capture(
                ct => service.ThrowIfContainsErrorRewriteErrors("a", ct));

            c1.Value.Should().Be("a");

            c2 = await Computed.Capture(
                ct => service.ThrowIfContainsErrorRewriteErrors("error", ct));

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorRewriteErrorsExceptionType);
            c2.Error.Message.Should().Be("!");

            await service.SetSuffix("z");

            c1 = await Update(c1);

            c1.Value.Should().Be("az");

            c2 = await Update(c2);

            c2.Error !.GetType().Should().Be(ThrowIfContainsErrorRewriteErrorsExceptionType);
            c2.Error.Message.Should().Be("!");
            await service.SetSuffix("");

            // ThrowIfContainsErrorRewriteErrorsAsync method test
            (await service.ThrowIfContainsErrorNonCompute("a")).Should().Be("a");
            try {
                await service.ThrowIfContainsErrorNonCompute("error");
            } catch (Exception e) { error = e; }
            error !.GetType().Should().Be(ThrowIfContainsErrorNonComputeExceptionType);
            error.Message.Should().Be("!");

            await service.SetSuffix("z");

            (await service.ThrowIfContainsErrorNonCompute("a")).Should().Be("az");
            try {
                await service.ThrowIfContainsErrorNonCompute("error");
            } catch (Exception e) { error = e; }
            error !.GetType().Should().Be(ThrowIfContainsErrorNonComputeExceptionType);
            error.Message.Should().Be("!");
            await service.SetSuffix("");
        }
Example #24
0
    public async Task DropReconnectTest()
    {
        if (TestRunnerInfo.IsBuildAgent())
        {
            // TODO: Fix intermittent failures on GitHub
            return;
        }

        var serving = await WebHost.Serve(false);

        var replicator = ClientServices.GetRequiredService <IReplicator>();
        var kvsClient  = ClientServices.GetRequiredService <IKeyValueServiceClient <string> >();

        Debug.WriteLine("0");
        var kvs = WebServices.GetRequiredService <IKeyValueService <string> >();
        await kvs.Set("a", "b");

        var c = (ReplicaMethodComputed <string>)
                await Computed.Capture(_ => kvsClient.Get("a"));

        c.Value.Should().Be("b");
        c.IsConsistent().Should().BeTrue();

        Debug.WriteLine("1");
        await c.Replica !.RequestUpdate().AsAsyncFunc()
        .Should().CompleteWithinAsync(TimeSpan.FromSeconds(5));

        c.IsConsistent().Should().BeTrue();

        Debug.WriteLine("2");
        var cs = replicator.GetPublisherConnectionState(c.Replica.PublicationRef.PublisherId);

        cs.Value.Should().BeTrue();
        cs.Computed.IsConsistent().Should().BeTrue();
        await cs.Recompute();

        Debug.WriteLine("3");
        cs.Value.Should().BeTrue();
        cs.Computed.IsConsistent().Should().BeTrue();
        var cs1 = replicator.GetPublisherConnectionState(c.Replica.PublicationRef.PublisherId);

        cs1.Should().BeSameAs(cs);

        Debug.WriteLine("WebServer: stopping.");
        await serving.DisposeAsync();

        Debug.WriteLine("WebServer: stopped.");

        // First try -- should fail w/ WebSocketException or ChannelClosedException
        c.IsConsistent().Should().BeTrue();
        c.Value.Should().Be("b");
        Debug.WriteLine("4");

        await cs.Update();

        cs.Error.Should().BeAssignableTo <Exception>();
        cs.Computed.IsConsistent().Should().BeTrue();
        var updateTask = c.Replica.RequestUpdate();

        updateTask.IsCompleted.Should().BeFalse();
        Debug.WriteLine("5");

        await kvs.Set("a", "c");

        await Delay(0.1);

        c.IsConsistent().Should().BeTrue();
        c.Value.Should().Be("b");
        Debug.WriteLine("6");

        Debug.WriteLine("WebServer: starting.");
        serving = await WebHost.Serve();
        await Delay(1);

        Debug.WriteLine("WebServer: started.");

        await TestExt.WhenMet(
            () => cs.Error.Should().BeNull(),
            TimeSpan.FromSeconds(30));

        Debug.WriteLine("7");

        await Delay(1);

        updateTask.IsCompleted.Should().BeTrue();
        c = (ReplicaMethodComputed <string>) await c.Update();

        c.IsConsistent().Should().BeTrue();
        c.Value.Should().Be("c");

        await serving.DisposeAsync();
    }