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 }
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); }
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); }
private async Task <IComputed <Screenshot> > GetScreenshotComputed() { var screenshots = Services.GetRequiredService <IScreenshotService>(); var computed = await Computed.Capture(_ => screenshots.GetScreenshot(1280)); return(computed); }
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"); }
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); }
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"); }
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 }
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); }
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 }
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); } }
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); } }
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)); }
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 }
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); }
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(); }
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(); }
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(""); }
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(); }