From cf425a4607981139f21a6dd05809801a94dc1940 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Fri, 6 Sep 2024 09:03:14 +0200 Subject: [PATCH] Updated consistency exercise --- .../05-Consistency/05-Consistency.csproj | 1 + .../05-Consistency/Core/Database.cs | 14 ++++++++++-- .../05-Consistency/Core/EventBus.cs | 2 +- .../05-Consistency/Core/TimeoutException.cs | 4 ++++ .../05-Consistency/05-Consistency.csproj | 1 + .../Solutions/05-Consistency/Core/Database.cs | 14 ++++++++++-- .../Solutions/05-Consistency/Core/EventBus.cs | 2 +- .../05-Consistency/Core/TimeoutException.cs | 3 +++ .../Sagas/Version1-Aggregates/Core/Retry.cs | 22 +++++++++++++++++++ .../GroupCheckouts/GroupCheckoutFacade.cs | 1 + 10 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 Workshops/EventDrivenArchitecture/05-Consistency/Core/TimeoutException.cs create mode 100644 Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/TimeoutException.cs create mode 100644 Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/Core/Retry.cs diff --git a/Workshops/EventDrivenArchitecture/05-Consistency/05-Consistency.csproj b/Workshops/EventDrivenArchitecture/05-Consistency/05-Consistency.csproj index d966d3e3..f7e1fc8e 100644 --- a/Workshops/EventDrivenArchitecture/05-Consistency/05-Consistency.csproj +++ b/Workshops/EventDrivenArchitecture/05-Consistency/05-Consistency.csproj @@ -16,6 +16,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all diff --git a/Workshops/EventDrivenArchitecture/05-Consistency/Core/Database.cs b/Workshops/EventDrivenArchitecture/05-Consistency/Core/Database.cs index 4f824c60..0cb7929c 100644 --- a/Workshops/EventDrivenArchitecture/05-Consistency/Core/Database.cs +++ b/Workshops/EventDrivenArchitecture/05-Consistency/Core/Database.cs @@ -12,7 +12,7 @@ public ValueTask Store(Guid id, T obj, CancellationToken _) where T : class try { if (DateTimeOffset.Now.Ticks % 5 == 0) - throw new InvalidOperationException("Database not available!"); + throw new TimeoutException("Database not available!"); storage[GetId(id)] = obj; @@ -30,7 +30,7 @@ public ValueTask Delete(Guid id, CancellationToken _) try { if (DateTimeOffset.Now.Ticks % 5 == 0) - throw new InvalidOperationException("Database not available!"); + throw new TimeoutException("Database not available!"); storage.Remove(GetId(id)); @@ -51,6 +51,16 @@ public ValueTask Delete(Guid id, CancellationToken _) : null ); + public ValueTask Filter(Func predicate, CancellationToken _) where T : class => + ValueTask.FromResult( + storage.Values + .OfType() + .Where(predicate) + .Select(record => + JsonSerializer.Deserialize(JsonSerializer.Serialize(record))! + ).ToArray() + ); + public async ValueTask Transaction(Func action) { Monitor.Enter(storage); diff --git a/Workshops/EventDrivenArchitecture/05-Consistency/Core/EventBus.cs b/Workshops/EventDrivenArchitecture/05-Consistency/Core/EventBus.cs index 8d8d697f..2bf3c3c2 100644 --- a/Workshops/EventDrivenArchitecture/05-Consistency/Core/EventBus.cs +++ b/Workshops/EventDrivenArchitecture/05-Consistency/Core/EventBus.cs @@ -7,7 +7,7 @@ public class EventBus public async ValueTask Publish(object[] events, CancellationToken ct) { if (DateTimeOffset.Now.Ticks % 5 == 0) - throw new InvalidOperationException("Database not available!"); + throw new TimeoutException("Database not available!"); foreach (var @event in events) { diff --git a/Workshops/EventDrivenArchitecture/05-Consistency/Core/TimeoutException.cs b/Workshops/EventDrivenArchitecture/05-Consistency/Core/TimeoutException.cs new file mode 100644 index 00000000..cd7673a3 --- /dev/null +++ b/Workshops/EventDrivenArchitecture/05-Consistency/Core/TimeoutException.cs @@ -0,0 +1,4 @@ +namespace Consistency.Core; + +public class TimeoutException(string message): Exception(message); + diff --git a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/05-Consistency.csproj b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/05-Consistency.csproj index d966d3e3..ae2f67bf 100644 --- a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/05-Consistency.csproj +++ b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/05-Consistency.csproj @@ -16,6 +16,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all diff --git a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/Database.cs b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/Database.cs index 4f824c60..0cb7929c 100644 --- a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/Database.cs +++ b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/Database.cs @@ -12,7 +12,7 @@ public ValueTask Store(Guid id, T obj, CancellationToken _) where T : class try { if (DateTimeOffset.Now.Ticks % 5 == 0) - throw new InvalidOperationException("Database not available!"); + throw new TimeoutException("Database not available!"); storage[GetId(id)] = obj; @@ -30,7 +30,7 @@ public ValueTask Delete(Guid id, CancellationToken _) try { if (DateTimeOffset.Now.Ticks % 5 == 0) - throw new InvalidOperationException("Database not available!"); + throw new TimeoutException("Database not available!"); storage.Remove(GetId(id)); @@ -51,6 +51,16 @@ public ValueTask Delete(Guid id, CancellationToken _) : null ); + public ValueTask Filter(Func predicate, CancellationToken _) where T : class => + ValueTask.FromResult( + storage.Values + .OfType() + .Where(predicate) + .Select(record => + JsonSerializer.Deserialize(JsonSerializer.Serialize(record))! + ).ToArray() + ); + public async ValueTask Transaction(Func action) { Monitor.Enter(storage); diff --git a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/EventBus.cs b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/EventBus.cs index 8d8d697f..2bf3c3c2 100644 --- a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/EventBus.cs +++ b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/EventBus.cs @@ -7,7 +7,7 @@ public class EventBus public async ValueTask Publish(object[] events, CancellationToken ct) { if (DateTimeOffset.Now.Ticks % 5 == 0) - throw new InvalidOperationException("Database not available!"); + throw new TimeoutException("Database not available!"); foreach (var @event in events) { diff --git a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/TimeoutException.cs b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/TimeoutException.cs new file mode 100644 index 00000000..402ea1de --- /dev/null +++ b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Core/TimeoutException.cs @@ -0,0 +1,3 @@ +namespace Consistency.Core; + +public class TimeoutException(string message): Exception(message); diff --git a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/Core/Retry.cs b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/Core/Retry.cs new file mode 100644 index 00000000..35976e7c --- /dev/null +++ b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/Core/Retry.cs @@ -0,0 +1,22 @@ +using Polly; +using Polly.Retry; + +namespace Consistency.Sagas.Version1_Aggregates.Core; + +public class Retry +{ + public static int RetriesCount; + + private static readonly AsyncRetryPolicy retryPolicy = Policy + .Handle() + .WaitAndRetryForeverAsync( + (_, _) => + { + RetriesCount++; + + return TimeSpan.FromMilliseconds(1); + }); + + public Task UntilSucceeds(Func handle, CancellationToken token = default) => + retryPolicy.ExecuteAsync(async ct => await handle(ct), token); +} diff --git a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/GroupCheckouts/GroupCheckoutFacade.cs b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/GroupCheckouts/GroupCheckoutFacade.cs index b28edc9f..8fc7428f 100644 --- a/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/GroupCheckouts/GroupCheckoutFacade.cs +++ b/Workshops/EventDrivenArchitecture/Solutions/05-Consistency/Sagas/Version1-Aggregates/GroupCheckouts/GroupCheckoutFacade.cs @@ -20,6 +20,7 @@ public async ValueTask InitiateGroupCheckout(InitiateGroupCheckout command, Canc command.Now ); + await database.Store(command.GroupCheckoutId, groupCheckout, ct); await eventBus.Publish(groupCheckout.DequeueUncommittedEvents(), ct); }