public async Task InvalidateEverythingTest() { var users = Services.GetRequiredService <IUserService>(); // We need at least 1 user to see count invalidation messages await users.CreateAsync(new User() { Id = int.MaxValue, Name = "Chuck Norris", }, true); var u1 = await users.TryGetAsync(int.MaxValue); var c1 = await Computed.CaptureAsync(_ => users.CountAsync()); users.Invalidate(); var u2 = await users.TryGetAsync(int.MaxValue); u2 !.IsFrozen.Should().BeTrue(); var c2 = await Computed.CaptureAsync(_ => users.CountAsync()); 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); }
private async Task <IComputed <Screenshot> > GetScreenshotComputedAsync() { var screenshots = Services.GetRequiredService <IScreenshotService>(); var computed = await Computed.CaptureAsync(_ => screenshots.GetScreenshotAsync(1280)); return(computed); }
public async Task Test1() { var epsilon = TimeSpan.FromSeconds(0.5); await using var serving = await WebSocketHost.ServeAsync(); var client = Services.GetRequiredService <IClientTimeService>(); var cTime = await Computed.CaptureAsync(_ => client.GetTimeAsync()); cTime.Options.AutoInvalidateTime.Should().Be(ComputedOptions.Default.AutoInvalidateTime); if (!cTime.IsConsistent()) { cTime = await cTime.UpdateAsync(false); cTime.IsConsistent().Should().BeTrue(); } (DateTime.Now - cTime.Value).Should().BeLessThan(epsilon); await TestEx.WhenMet( () => cTime.IsConsistent().Should().BeFalse(), TimeSpan.FromSeconds(5)); var time = await cTime.UseAsync(); (DateTime.Now - time).Should().BeLessThan(epsilon); }
public async Task InvalidationAndCachingTest2() { // TODO: Fix the test so that it starts right after the time invalidation, // otherwise it has a tiny chance of failure var time = Services.GetRequiredService <ITimeService>(); var c1 = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); c1.Should().NotBeNull(); var c2 = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2))); c2.Should().NotBeNull(); c1.Should().NotBeSameAs(c2); var c1a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); var c2a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2))); c1.Should().BeSameAs(c1a); c2.Should().BeSameAs(c2a); // Wait for time invalidation await Task.Delay(500); c1a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); c2a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2))); c1.Should().NotBeSameAs(c1a); c2.Should().NotBeSameAs(c2a); }
public async Task BasicTest() { var kvs = Services.GetRequiredService <IKeyValueStore>(); var c1 = await Computed.CaptureAsync(_ => kvs.TryGetAsync("1")); var c2 = await Computed.CaptureAsync(_ => kvs.TryGetAsync("2")); var c3 = await Computed.CaptureAsync(_ => kvs.TryGetAsync("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.CallAsync(command); c1.IsInvalidated().Should().BeTrue(); c2.IsInvalidated().Should().BeTrue(); c3.IsInvalidated().Should().BeTrue(); c1 = await c1.UpdateAsync(false); c2 = await c2.UpdateAsync(false); c3 = await c3.UpdateAsync(false); c1.Value.Should().Be("v3"); c2.Value.Should().Be("v2"); c3.Value.Should().Be("v1"); }
public async Task AutoRecomputeTest() { var time = Services.GetRequiredService <ITimeService>(); var c = await Computed.CaptureAsync( _ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); var count = 0L; using var state = StateFactory.NewLive <DateTime>( o => o.WithZeroUpdateDelay(), async(_, ct) => await c.UseAsync(ct)); state.Updated += s => Log.LogInformation($"{++count} -> {s.Value:hh:mm:ss:fff}"); await TestEx.WhenMet( () => count.Should().BeGreaterThan(2), TimeSpan.FromSeconds(5)); var lastCount = count; state.Dispose(); await Task.Delay(1000); count.Should().Be(lastCount); }
public async Task BasicTest() { var services = CreateServiceProviderFor <MathService>(); var math = services.GetRequiredService <MathService>(); var allComputed = new HashSet <IComputed>(); var c1 = await Computed.CaptureAsync(_ => math.SumAsync(null)); c1.Value.Should().Be(0); allComputed.Add(c1); var c2 = await Computed.CaptureAsync(_ => math.SumAsync(null)); c2.Should().BeSameAs(c1); for (var i = 0; i < 20; i++) { var values = Enumerable.Range(0, i).ToArray(); c1 = await Computed.CaptureAsync(_ => math.SumAsync(values)); c1.Value.Should().Be(values.Sum()); allComputed.Add(c1); c2 = await Computed.CaptureAsync(_ => math.SumAsync(values)); c2.Should().BeSameAs(c1); } allComputed.Count.Should().Be(21); }
public static async Task <IPublication <T> > PublishAsync <T>( this IPublisher publisher, Func <CancellationToken, Task <T> > producer, CancellationToken cancellationToken = default) { var computed = await Computed .CaptureAsync(producer, cancellationToken) .ConfigureAwait(false); 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.UpdateAsync(cancellationToken); } catch (OperationCanceledException) { throw; } catch { // Intended } return(publication); }
public static async Task UseCalculator5() { #region part04_useCalculator5 var calc = Create <Calculator>(); var s1 = await calc.SumAsync(1, 1); WriteLine($"{nameof(s1)} = {s1}"); // Now let's pull the computed instance that represents the result of // Notice that the underlying SumAsync code won't be invoked, // since the result is already cached: var c1 = await Computed.CaptureAsync(_ => calc.SumAsync(1, 1)); WriteLine($"{nameof(c1)} = {c1}, Value = {c1.Value}"); // And invalidate it c1.Invalidate(); WriteLine($"{nameof(c1)} = {c1}, Value = {c1.Value}"); // Let's compute the sum once more now. // You'll see that SumAsync gets invoked this time. s1 = await calc.SumAsync(1, 1); WriteLine($"{nameof(s1)} = {s1}"); #endregion }
public async Task BasicTest() { var liveClock = Services.GetRequiredService <ILiveClock>(); var cTime = await Computed.CaptureAsync(_ => liveClock.GetUtcNowAsync()); cTime.IsConsistent().Should().BeTrue(); (DateTime.UtcNow - cTime.Value).Should().BeLessThan(TimeSpan.FromSeconds(1.1)); await DelayAsync(1.3); cTime.IsConsistent().Should().BeFalse(); cTime = await Computed.CaptureAsync(_ => liveClock.GetUtcNowAsync(TimeSpan.FromMilliseconds(200))); cTime.IsConsistent().Should().BeTrue(); await DelayAsync(0.25); cTime.IsConsistent().Should().BeFalse(); var now = DateTime.UtcNow; var ago = await liveClock.GetMomentsAgoAsync(now); ago.Should().Be("just now"); await DelayAsync(1.8); ago = await liveClock.GetMomentsAgoAsync(now); ago.Should().Be("1 second ago"); }
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.CaptureAsync(_ => counters.GetAsync("a")); WriteLine($"{DateTime.Now}: {computed.Value}"); for (var i = 0; i < 5; i++) { await computed.WhenInvalidatedAsync(); computed = await computed.UpdateAsync(false); WriteLine($"{DateTime.Now}: {computed.Value}"); } #endregion }
public async Task KeepAliveTimeTest() { var users = Services.GetRequiredService <IUserService>(); var cUser0 = await Computed.CaptureAsync(_ => users.TryGetAsync(0)); var cCount = await Computed.CaptureAsync(_ => users.CountAsync()); 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.CaptureAsync(_ => counters.GetAsync("a")); WriteLine($"Computed: {computed}"); WriteLine($"- IsConsistent(): {computed.IsConsistent()}"); WriteLine($"- Value: {computed.Value}"); #endregion }
public static Task <IComputed <T> > MaybePublishAsync <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.PublishAsync(publisher, producer, cancellationToken) : Computed.CaptureAsync(producer, cancellationToken)); }
public async Task ExceptionCaptureTest() { var p = Services.GetRequiredService <ISimplestProvider>(); p.SetValue(null !); // Will cause an exception in GetCharCountAsync var c1 = await Computed.TryCaptureAsync(_ => p.GetCharCountAsync()); var c2 = await Computed.CaptureAsync(_ => p.GetCharCountAsync()); c1 !.Error !.GetType().Should().Be(typeof(NullReferenceException)); c2.Should().BeSameAs(c1); }
public static async Task Caching4() { #region Part05_Caching4 var service = CreateServices().GetRequiredService <Service2>(); var computed = await Computed.CaptureAsync(_ => service.GetAsync("a")); WriteLine("computed = GetAsync(a) completed"); WriteLine(await service.CombineAsync("a", "b")); GC.Collect(); WriteLine("GC.Collect() completed"); WriteLine(await service.CombineAsync("a", "b")); #endregion }
public static async Task Caching2() { #region Part05_Caching2 var service = CreateServices().GetRequiredService <Service1>(); var computed = await Computed.CaptureAsync(_ => service.GetAsync("a")); WriteLine(await service.GetAsync("a")); WriteLine(await service.GetAsync("a")); GC.Collect(); WriteLine("GC.Collect()"); WriteLine(await service.GetAsync("a")); WriteLine(await service.GetAsync("a")); #endregion }
public static async Task InvalidateComputed2() { #region Part02_InvalidateComputed2 var counters = CreateServices().GetRequiredService <CounterService>(); var computed = await Computed.CaptureAsync(_ => counters.GetAsync("a")); WriteLine($"computed: {computed}"); WriteLine("Computed.Invalidate(() => counters.GetAsync(\"a\"))"); Computed.Invalidate(() => counters.GetAsync("a")); // <- This line WriteLine($"computed: {computed}"); var newComputed = await Computed.CaptureAsync(_ => counters.GetAsync("a")); // <- This line WriteLine($"newComputed: {newComputed}"); #endregion }
public static async Task InvalidateComputed1() { #region Part02_InvalidateComputed1 var counters = CreateServices().GetRequiredService <CounterService>(); var computed = await Computed.CaptureAsync(_ => counters.GetAsync("a")); WriteLine($"computed: {computed}"); WriteLine("computed.Invalidate()"); computed.Invalidate(); WriteLine($"computed: {computed}"); var newComputed = await computed.UpdateAsync(false); WriteLine($"newComputed: {newComputed}"); #endregion }
public async Task InvalidationAndCachingTest1() { var time = Services.GetRequiredService <ITimeService>(); var c1 = await Computed.CaptureAsync(_ => time.GetTimeAsync()); // Wait for time invalidation await Task.Delay(500); var c2a = await Computed.CaptureAsync(_ => time.GetTimeAsync()); c2a.Should().NotBeSameAs(c1); var c2b = await Computed.CaptureAsync(_ => time.GetTimeAsync()); c2b.Should().BeSameAs(c2a); }
public async Task BasicTest() { if (OSInfo.Kind == OSKind.Unix) { // Screenshots don't work on Unix return; } var screenshots = Services.GetRequiredService <IScreenshotService>(); var c = await Computed.CaptureAsync(_ => screenshots.GetScreenshotAsync(128)); c.IsConsistent.Should().BeTrue(); c.Value.Length.Should().BeGreaterThan(0); await Task.Delay(200); c.IsConsistent.Should().BeFalse(); }
public async Task Test1() { var epsilon = TimeSpan.FromSeconds(0.5); await using var serving = await WebSocketHost.ServeAsync(); var client = Services.GetRequiredService <IClientTimeService>(); var cTime = await Computed.CaptureAsync(_ => client.GetTimeAsync()); cTime.IsConsistent.Should().BeTrue(); (DateTime.Now - cTime.Value).Should().BeLessThan(epsilon); await Task.Delay(TimeSpan.FromSeconds(2)); cTime.IsConsistent.Should().BeFalse(); var time = await cTime.UseAsync(); (DateTime.Now - time).Should().BeLessThan(epsilon); }
public async Task OptionsTest() { var d = ComputedOptions.Default; var p = Services.GetRequiredService <ISimplestProvider>(); p.SetValue(""); var c1 = await Computed.CaptureAsync(_ => p.GetValueAsync()); 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.CaptureAsync(_ => p.GetCharCountAsync()); 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); }
static async Task Main(string[] args) { var services = new ServiceCollection() .AddFusion() .AddComputeService <UserService>() .AddComputeService <GreetingService>() .BackToServices() .BuildServiceProvider(); var users = services.GetRequiredService <UserService>(); var greetings = services.GetRequiredService <GreetingService>(); var userId = 1; var user = new User(userId, "(name isn't set yet)"); await users.AddOrUpdateUserAsync(user); Task.Run(async() => { var computed = await Computed.CaptureAsync(_ => greetings.GreetUserAsync(userId)); while (true) { Console.WriteLine($"Background task: {computed.Value}"); // Wait for invalidation of GreetUserAsync(userId) result (IComputed); // The invalidation is triggered by the following chain: // AddOrUpdateUserAsync -> GetUserAsync -> GreetUserAsync. await computed.WhenInvalidatedAsync(); // Computed instances are immutable, so we need // to get a new one to observe the updated value. computed = await computed.UpdateAsync(false); } }).Ignore(); // Notice the code below doesn't even know there are some IComputed, etc. while (true) { Console.WriteLine("What's your name?"); var name = Console.ReadLine() ?? ""; await users.AddOrUpdateUserAsync(new User(userId, name)); var greeting = await greetings.GreetUserAsync(userId); Console.WriteLine(greeting); } }
public async Task CounterServiceTest() { using var stopCts = new CancellationTokenSource(); var cancellationToken = stopCts.Token; async Task WatchAsync <T>(string name, IComputed <T> computed) { for (;;) { Out.WriteLine($"{name}: {computed.Value}, {computed}"); await computed.WhenInvalidatedAsync(cancellationToken); Out.WriteLine($"{name}: {computed.Value}, {computed}"); computed = await computed.UpdateAsync(false, cancellationToken); } } var services = CreateServiceProviderFor <CounterService>(); var counters = services.GetService <CounterService>(); var aComputed = await Computed.CaptureAsync(_ => counters.GetAsync("a")); Task.Run(() => WatchAsync(nameof(aComputed), aComputed)).Ignore(); var bComputed = await Computed.CaptureAsync(_ => counters.GetAsync("b")); Task.Run(() => WatchAsync(nameof(bComputed), bComputed)).Ignore(); await counters.IncrementAsync("a"); await counters.SetOffsetAsync(10); aComputed = await aComputed.UpdateAsync(false); aComputed.Value.Should().Be(11); aComputed.IsConsistent().Should().BeTrue(); bComputed = await bComputed.UpdateAsync(false); 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.TryGetExisting(() => counters.GetAsync("a")); c.Should().BeNull(); c = await Computed.CaptureAsync(_ => counters.GetAsync("a")); c.Value.Should().Be(0); var c1 = Computed.TryGetExisting(() => counters.GetAsync("a")); c1.Should().BeSameAs(c); await counters.IncrementAsync("a"); c.IsConsistent().Should().BeFalse(); c1 = Computed.TryGetExisting(() => counters.GetAsync("a")); c1.Should().BeNull(); }
public static async Task UseServices_Part2() { #region part05_useServices_part2 var services = CreateServiceProvider(); var users = services.GetRequiredService <UserRegistry>(); var formatter = services.GetRequiredService <FormatService>(); users.SetUserName(0, "John Carmack"); var cFormattedUser0 = await Computed.CaptureAsync(async _ => await formatter.FormatUserNameAsync(0)); for (var i = 0; i < 10; i++) { WriteLine(cFormattedUser0.Value); await cFormattedUser0.WhenInvalidatedAsync(); // Note that nothing gets recomputed automatically; // on a positive side, any IComputed knows how to recompute itself, // so you can always do this manually: cFormattedUser0 = await cFormattedUser0.UpdateAsync(false); } #endregion }
public async Task AutoRecomputeTest() { var time = Services.GetRequiredService <ITimeService>(); var c = await Computed.CaptureAsync( _ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); var count = 0L; void OnInvalidated(IComputed <DateTime> @new, Result <DateTime> old, Exception?updateError) => Log.LogInformation($"{++count} -> {@new.Value:hh:mm:ss:fff}"); using (var _ = c !.AutoUpdate(OnInvalidated)) { await Task.Delay(3000); } var lastCount = count; Out.WriteLine("Completed AutoRecompute."); await Task.Delay(1000); count.Should().Be(lastCount); count.Should().BeGreaterThan(3); }
public async Task BasicTest() { using var stopCts = new CancellationTokenSource(); var cancellationToken = stopCts.Token; async Task WatchAsync <T>(string name, IComputed <T> computed) { for (;;) { Out.WriteLine($"{name}: {computed.Value}, {computed}"); await computed.WhenInvalidatedAsync(cancellationToken); Out.WriteLine($"{name}: {computed.Value}, {computed}"); computed = await computed.UpdateAsync(false, 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.CaptureAsync(_ => counters.GetAsync("a", session)); Task.Run(() => WatchAsync(nameof(aaComputed), aaComputed)).Ignore(); var abComputed = await Computed.CaptureAsync(_ => counters.GetAsync("b", session)); Task.Run(() => WatchAsync(nameof(abComputed), abComputed)).Ignore(); session = sessionB; var baComputed = await Computed.CaptureAsync(_ => counters.GetAsync("a", session)); Task.Run(() => WatchAsync(nameof(baComputed), baComputed)).Ignore(); session = sessionA; await counters.IncrementAsync("a", session); (await aaComputed.UpdateAsync(false)).Value.Should().Be(1); (await abComputed.UpdateAsync(false)).Value.Should().Be(0); (await baComputed.UpdateAsync(false)).Value.Should().Be(0); await counters.IncrementAsync("b", session); (await aaComputed.UpdateAsync(false)).Value.Should().Be(1); (await abComputed.UpdateAsync(false)).Value.Should().Be(1); (await baComputed.UpdateAsync(false)).Value.Should().Be(0); session = sessionB; await counters.IncrementAsync("a", session); (await aaComputed.UpdateAsync(false)).Value.Should().Be(1); (await abComputed.UpdateAsync(false)).Value.Should().Be(1); (await baComputed.UpdateAsync(false)).Value.Should().Be(1); await counters.IncrementAsync("b", session); (await aaComputed.UpdateAsync(false)).Value.Should().Be(1); (await abComputed.UpdateAsync(false)).Value.Should().Be(1); (await baComputed.UpdateAsync(false)).Value.Should().Be(1); stopCts.Cancel(); }
private async Task ActualTest(IEdgeCaseService service) { var error = (Exception?)null; await service.SetSuffixAsync(""); (await service.GetSuffixAsync()).Should().Be(""); // ThrowIfContainsErrorAsync method test var c1 = await Computed.CaptureAsync( ct => service.ThrowIfContainsErrorAsync("a", ct)); c1.Value.Should().Be("a"); var c2 = await Computed.CaptureAsync( ct => service.ThrowIfContainsErrorAsync("error", ct)); c2.Error !.GetType().Should().Be(ThrowIfContainsErrorExceptionType); c2.Error.Message.Should().Be("!"); await service.SetSuffixAsync("z"); c1 = await UpdateAsync(c1); c1.Value.Should().Be("az"); c2 = await UpdateAsync(c2); c2.Error !.GetType().Should().Be(ThrowIfContainsErrorExceptionType); c2.Error.Message.Should().Be("!"); await service.SetSuffixAsync(""); // ThrowIfContainsErrorRewriteErrorsAsync method test c1 = await Computed.CaptureAsync( ct => service.ThrowIfContainsErrorRewriteErrorsAsync("a", ct)); c1.Value.Should().Be("a"); c2 = await Computed.CaptureAsync( ct => service.ThrowIfContainsErrorRewriteErrorsAsync("error", ct)); c2.Error !.GetType().Should().Be(ThrowIfContainsErrorRewriteErrorsExceptionType); c2.Error.Message.Should().Be("!"); await service.SetSuffixAsync("z"); c1 = await UpdateAsync(c1); c1.Value.Should().Be("az"); c2 = await UpdateAsync(c2); c2.Error !.GetType().Should().Be(ThrowIfContainsErrorRewriteErrorsExceptionType); c2.Error.Message.Should().Be("!"); await service.SetSuffixAsync(""); // ThrowIfContainsErrorRewriteErrorsAsync method test (await service.ThrowIfContainsErrorNonComputeAsync("a")).Should().Be("a"); try { await service.ThrowIfContainsErrorNonComputeAsync("error"); } catch (Exception e) { error = e; } error !.GetType().Should().Be(ThrowIfContainsErrorNonComputeExceptionType); error.Message.Should().Be("!"); await service.SetSuffixAsync("z"); (await service.ThrowIfContainsErrorNonComputeAsync("a")).Should().Be("az"); try { await service.ThrowIfContainsErrorNonComputeAsync("error"); } catch (Exception e) { error = e; } error !.GetType().Should().Be(ThrowIfContainsErrorNonComputeExceptionType); error.Message.Should().Be("!"); await service.SetSuffixAsync(""); }