Slide 1

Slide 1 text

🔮 Event Sourcing in Azure Which database to use?

Slide 2

Slide 2 text

🖖 Hello! @spontoreau Sylvain Pontoreau 🎪 Co-organizer 📕 Book writer Microsoft 󰳕 Work with

Slide 3

Slide 3 text

📖 Time for self-promotion

Slide 4

Slide 4 text

🕺 Why I am talking about this topic ? I have been diving deep in it for a long time!

Slide 5

Slide 5 text

❓ What is Event Sourcing

Slide 6

Slide 6 text

💁 The Event Sourcing pattern “Every change to the state of an application is captured in an event” https://martinfowler.com/eaaDev/EventSourcing.html

Slide 7

Slide 7 text

✨ Event sourcing benefits Rebuild Temporal queries Replay

Slide 8

Slide 8 text

🎭 Event sourcing use cases Audit Debug Consistency

Slide 9

Slide 9 text

🗄 Event Store Sequence of events Event immutability Single point of Truth

Slide 10

Slide 10 text

📨 Event Stream Sequence of events = Event Stream Event Stream Event Event Event Event Event Event Event Event Event Timeline

Slide 11

Slide 11 text

📨 Event Stream Load from stream Event Event Event Event Event Event Event Event Event Load Reduce State

Slide 12

Slide 12 text

📨 Event Stream Append event Event Event Event Event Event Event Event Event Event Append Event

Slide 13

Slide 13 text

📨 Event Stream Subscribe Event Event Event Event Event Event Event Event Event Append Event Subscribe

Slide 14

Slide 14 text

📰 Read operations Load Reduce State A little bit expensive for read operations… … and not really great for querying :(

Slide 15

Slide 15 text

📽 Projections Using subscribe to build a queryable representation of the application state (aka Projections) Subscribe Projections Projector ℹ A good database for event sourcing must have a data streaming mechanism

Slide 16

Slide 16 text

✋ Keep that in mind App DB Projections Append Subscribe App Projections Append Publish ✅ ❌ DB ❗ Even if you’re using a Message Broker or an Event Bus

Slide 17

Slide 17 text

⚠ Eventually consistent CAP Theorem (Eric Brewer) Consistency Availability Partition tolerance All system nodes needs to manipulate exactly the same data at the same time Requests must succeed Node failure must not create a complete system failure A distributed system can only guarantee 2 constraints at the same time, not 3…

Slide 18

Slide 18 text

🔃 CQRS pattern What is CQRS? • A pattern designed by Greg Young • Command Query Responsibility Segregation • Read != Write (different needs) Query A read operation Command Validation Business logic Persistence CQRS suit perfectly well with Event Sourcing!

Slide 19

Slide 19 text

🔃 CQRS pattern GetBalance Query Deposite Command GetAllOperation Query Withdraw Command … … Dispatcher Read DB Dispatcher QueryHandler CommandHandler Event Store Projection Projection Aggregate State Events Behaviors

Slide 20

Slide 20 text

☁ Azure Flexibility Hyper scale Out of the box

Slide 21

Slide 21 text

🗃 PostgreSQL - Table CREATE TABLE "EVENT_STREAM" ( "streamId" VARCHAR NOT NULL, "createdAt" VARCHAR NOT NULL, "type" VARCHAR NOT NULL, "version" INTEGER NOT NULL, "payload" JSONB, PRIMARY KEY ("streamId", "createdAt", "version") ); CREATE INDEX ON "EVENT_STREAM" ("streamId");

Slide 22

Slide 22 text

🗃 PostgreSQL - Notify CREATE FUNCTION notify_new_event() RETURNS TRIGGER AS $trigger$ BEGIN PERFORM pg_notify('new_event', row_to_json(NEW)::text); RETURN NULL; END; $trigger$ LANGUAGE plpgsql VOLATILE COST 100;

Slide 23

Slide 23 text

🗃 PostgreSQL - Trigger CREATE TRIGGER notify_new_event AFTER INSERT ON "EVENT_STREAM" FOR EACH ROW EXECUTE PROCEDURE notify_new_event();

Slide 24

Slide 24 text

🗃 PostgreSQL - Rules CREATE FUNCTION THROW_WHEN_TYRING_TO_UPDATE_EVENT_STREAM() RETURNS VOID AS $$ BEGIN RAISE EXCEPTION 'Event Stream can not be updated'; END; $$ LANGUAGE plpgsql VOLATILE; CREATE RULE "PREVENT_DELETE_ON_EVENT_STREAM" AS ON DELETE TO "EVENT_STREAM" DO INSTEAD SELECT THROW_WHEN_TYRING_TO_UPDATE_EVENT_STREAM(); CREATE RULE "PREVENT_UPDATE_ON_EVENT_STREAM" AS ON UPDATE TO "EVENT_STREAM" DO INSTEAD SELECT THROW_WHEN_TYRING_TO_UPDATE_EVENT_STREAM();

Slide 25

Slide 25 text

🗃 PostgreSQL - Load events SELECT "type", "payload", "version" FROM "EVENT_STREAM" WHERE "streamId" = $1 ORDER BY "createdAt", "version"

Slide 26

Slide 26 text

🗃 PostgreSQL - Append events INSERT INTO "EVENT_STREAM" ( "streamId", "createdAt", "type", "version", "payload" ) VALUES ($1, $2, $3, ( SELECT COUNT("streamId") + 1 FROM "EVENT_STREAM" WHERE "streamId" = $5 ), $4 )

Slide 27

Slide 27 text

🗃 PostgreSQL - Conclusion ✅ ❌ • Simple to implement • One impl for all languages • On premise if needed • DB Tuning • You must know how to do it • Distributed • No acknowledgement

Slide 28

Slide 28 text

🗃 SQL Server The same thing but with “Service Broker” 😅

Slide 29

Slide 29 text

🌐 Cosmos DB Change feed for the win! Change Feed Event Stream Data

Slide 30

Slide 30 text

🌐 Cosmos DB Table, Trigger, Notify ➡ Nothing to do !!!

Slide 31

Slide 31 text

🌐 Cosmos DB - Load stream const endpoint = "https://your-account.documents.azure.com"; const key = ""; const client = new CosmosClient({ endpoint, key }); const container = client.database("EventStore").container("EventStream"); const querySpec: SqlQuerySpec = { query: `SELECT eventStream.eventType, eventStream.payload, eventStream.version, FROM eventStream WHERE eventStream.streamId = @streamId ORDER BY eventStream.createdAt, eventStream.version`, parameters: [{ name: "@streamId", value: "" } ] }; const { resources } = await container.items.query(querySpec).fetchAll();

Slide 32

Slide 32 text

🌐 Cosmos DB - Append events const endpoint = "https://your-account.documents.azure.com"; const key = ""; const client = new CosmosClient({ endpoint, key }); const container = client.database("EventStore").container("EventStream"); await container.items.create({ streamId: "", createdAt: "", version: , payload: { //… } });

Slide 33

Slide 33 text

🌐 Cosmos DB - Conclusion ✅ ❌ • Straightforward • Serverless • Schemaless • No rules • Version computed in code

Slide 34

Slide 34 text

🌀 Event Store DB Install the SDK and enjoy 🥳

Slide 35

Slide 35 text

🌀 Event Store DB - Load stream const client = new EventStoreDBClient({ endpoint: "", }); const streamName = ""; const events = client.readStream(streamName, { fromRevision: START, direction: FORWARDS, maxCount: 10, });

Slide 36

Slide 36 text

🌀 Event Store DB - Append events const client = new EventStoreDBClient({ endpoint: "", }); const streamName = ""; const event = jsonEvent({ type: "", data: { //… }, }); await client.appendToStream(streamName, [event]);

Slide 37

Slide 37 text

🌀 Event Store DB ✅ • Out of the box • State of the art • Built in projection • On premise if needed • Manage outside of Azure… • Not too much customization • Only gRPC client ❌

Slide 38

Slide 38 text

Conclusion

Slide 39

Slide 39 text

Questions❓

Slide 40

Slide 40 text

🔮 Thanks!