Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
LEVELUP 2015 - Enterprise software schaalbaar maken met Service Fabric
Search
Michiel Overeem
November 26, 2015
Technology
0
200
LEVELUP 2015 - Enterprise software schaalbaar maken met Service Fabric
hoe AFAS zijn next gen ERP platform ontwikkelt
Michiel Overeem
November 26, 2015
Tweet
Share
More Decks by Michiel Overeem
See All by Michiel Overeem
Reminiscing a crazy journey: building an event sourced ERP system
overeemm
0
67
EventSourcing.Live 2021 - A system with thousands of event types
overeemm
0
240
EventSourcing.Live 2021 - Event system evolution - A Scientific Study on Event Sourcing, Lessons from Industry
overeemm
0
220
DDDVienna - 103 years of event sourcing experience
overeemm
0
330
DDDVienna - Applying event sourcing and CQRS in a large ERP system
overeemm
1
970
Landelijk Architectuur Congres - The dark side of event sourcing: managing data conversion
overeemm
0
270
Dutch .NET Group Meetup - Building an event sourced system in .NET
overeemm
0
310
Drukwerkdeal.nl Developer Meetup - Event Sourcing After Launch
overeemm
0
180
DDDEurope 2018 - Event Sourcing After Launch
overeemm
5
2.3k
Other Decks in Technology
See All in Technology
強みを伸ばすキャリアデザイン
yug1224
0
200
Next'24 事例セッションの紹介とクラウド資格を活用したキャリア形成について語りMuscle
yasumuusan
0
250
アプリがつくるNOT A HOTELブランド
hokuts
0
450
PHPカンファレンス小田原2024
ysknsid25
2
660
Autonomous Database Cloud 技術詳細 / adb-s_technical_detail_jp
oracle4engineer
PRO
13
35k
自動生成を活用した、運用保守コストを抑える Error/Alert/Runbook の一元集約管理 / Centralized management of Error/Alert/Runbook to minimize operational costs using automated code generation
biwashi
9
2k
検証を通して見えてきたTiDBの性能特性
lycorptech_jp
PRO
5
2.3k
Databricks におけるデータエンジニアリング
databricksjapan
0
370
Discord とビルダー&チャットボットの使い方 / How to use Discord and Builder & Chatbots
ks91
PRO
0
130
マルチアカウント環境への発見的統制の導入
ch1aki
1
1.3k
エンタープライズ環境下での Active Directory の運用 TIPS
tamaiyutaro
1
1.5k
スタートアップの技術顧問を3年間続けて発生した事と気付き
biwakonbu
0
150
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
185
16k
Making the Leap to Tech Lead
cromwellryan
123
8.5k
4 Signs Your Business is Dying
shpigford
175
21k
How GitHub (no longer) Works
holman
304
140k
Optimising Largest Contentful Paint
csswizardry
7
2.3k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
1
3.4k
The Language of Interfaces
destraynor
151
23k
Design by the Numbers
sachag
274
18k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
352
28k
Creatively Recalculating Your Daily Design Routine
revolveconf
209
11k
Atom: Resistance is Futile
akmur
258
25k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
153
14k
Transcript
Enterprise software schaalbaar maken met Service Fabric hoe AFAS zijn
next gen ERP platform ontwikkelt
360+ medewerkers (4 locaties) 10.000 klanten (bedrijven) 1.500.000 gebruikers 80
miljoen euro omzet (2014) AFAS Software
AFAS Profit Maandelijks 1.500.000 loonstroken HRM, CRM, financieel, order management,
project management, workflow, ...
AFAS Online 1780 cores, 25 TB RAM, 180 TB SSD
storage 10.000 concurrent RDP gebruikers 200.000 unieke gebruikers per maand 1.500.000 API calls per dag
Software kun je definiëren in plaats van programmeren.
Modelleer het bedrijf met zijn processen
Sla het model op in een definitie
Lees de definitie in een generator
Lever de resulterende applicatie uit
None
client command-systeem query-systeem event bus
Command public class CreateArticleCommand : Command { public Guid ArticleId
{ get; set; } public string Description { get; set; } public decimal Price { get; set; } } Event public class ArticleCreatedEvent : Event { public Guid ArticleId { get; set; } public string Description { get; set; } public decimal Price { get; set; } } Query public class GetArticleQuery : Query { public Guid ArticleId { get; set; } }
client query-systeem event bus command-systeem
AggregateRoot - Handle public void Handle(CreateArticleCommand command) { if(command.Price <=
0) { throw new CommandValidationException("Price should be greater than 0."); } if(string.IsNullOrEmpty(command.Description) || command.Description.Length > 20) { throw new CommandValidationException("Description is mandatory, " + "and cannot be longer than 20 characters."); } RaiseEvent(new ArticleCreatedEvent(command.ArticleId, command.Description, command.Price)); } AggregateRoot - Apply private void Apply(ArticleCreatedEvent @event) { _saleable = true; _price = @event.Price; }
client query-systeem event bus
CommandHandler private void Handle(CreateArticleCommand command) { Repository.ExecuteOn<ArticleAggregateRoot>(command.ArticleId, command); } AggregateRootRepository
- InMemory public virtual async Task ExecuteOn<T>(Guid aggregateId, Command command) where T: AggregateRoot { T aggregateRoot = LoadAggregateRoot<T>(aggregateId); aggregateRoot.Handle(command); await SaveAndDispatchEvents(aggregateRoot); }
1 3 7 4 8 2 8 6 5 1
3 1 4 6 2 7 6 5 4 8 3 7 2 5
“Actors are isolated, single-threaded components that encapsulate both state and
behavior.”
1 3 7 4 8 2 8 6 5 1
3 1 4 6 2 7 6 5 4 8 3 7 2 5
service systeem reliable collections communicatie actors service API service systeem
reliable collections communicatie service API
client query-systeem event bus
AggregateRootRepository - InMemory public virtual async Task ExecuteOn<T>(Guid aggregateId, Command
command) where T: AggregateRoot { T aggregateRoot = LoadAggregateRoot<T>(aggregateId); aggregateRoot.Handle(command); await SaveAndDispatchEvents(aggregateRoot); } AggregateRootRepository – Service Fabric public override async Task ExecuteOn<T>(Guid aggregateId, Command command) { var actor = ActorProxy.Create<IAggregateRootActor>(new ActorId(aggregateId), "App"); await actor.ExecuteOn(typeof(T).AssemblyQualifiedName, command.ToJson()); }
AggregateRootActor public async Task ExecuteOn(string aggregateRootType, string commandJson) { var
aggregateRoot = LoadAggregateRoot(aggregateRootType); var command = Deserialize(commandJson); aggregateRoot.Handle(command); await SaveAndDispatchEvents(aggregateRoot); }
één Stateless Actor Type Range partitions voor load balancing Actor
Id is het Id van de AggregateRoot
client command-systeem event bus query-systeem
QueryModelBuilder private void Handle(ArticleCreatedEvent @event) { Repository.Add(@event.ArticleId, new JObject( new
JProperty("Article", @event.ArticleId), new JProperty("Description", @event.Description), new JProperty("Price", @event.Price))); } QueryHandler private JObject Handle(GetArticleQuery query) { return Repository.Get(query.ArticleId); }
client command-systeem event bus
client command-systeem event bus
QueryModelBuilder Service public async Task Handle(string eventJson) { var queue
= await StateManager.GetOrAddAsync<IReliableQueue<string>>("qmbQueue"); using(ITransaction tx = StateManager.CreateTransaction()) { await queue.EnqueueAsync(tx, eventJson); await tx.CommitAsync(); } }
QueryModelBuilder Service protected override async Task RunAsync(CancellationToken cancellationToken) { var
queue = await StateManager.GetOrAddAsync<IReliableQueue<string>>("qmbQueue"); while(true) { using(ITransaction tx = StateManager.CreateTransaction()) { ConditionalResult<string> dequeueReply = await queue.TryDequeueAsync(tx); if(dequeueReply.HasValue) { string message = dequeueReply.Value; _queryModelBuilder.Handle(Deserialize(message)); await tx.CommitAsync(); } } } }
één Stateful Service Type Named partitions voor load balancing Partition
name is het type van de QueryModelBuilder
None
Voor vragen, discussie etc:
[email protected]
- @michielovereem - https://linkedin.com/in/movereem CQRS
+ Service Fabric • Sluit ontzettend goed aan bij onze architectuur. • Betrouwbaarheid, schaalbaarheid en onderhoudsgemak. • Portable cloud hosting is mogelijk. https://github.com/AFASSoftware/CQRS-Microservices