Slide 1

Slide 1 text

SEPTEMBER 19 -20, 2024 - LILLE, FRANCE & ONLINE Real-time message handling and notifications with API Platform and Symfony

Slide 2

Slide 2 text

About me Allison Guilhem ✔ Lead developer, Les-Tilleuls.coop ✔ Contributor to Symfony and API Platform @Alli_g83 Allison E. Guilhem

Slide 3

Slide 3 text

Real time notifications with Mercure via a use case scenario 01 02 Real time notifications: techniques and protocols

Slide 4

Slide 4 text

01 - Real time notifications: techniques and protocols

Slide 5

Slide 5 text

HTTP Protocol ✔ Designed to transfer hypertext documents between a client and a server ✔ Request-response model ✔ HTTP1.0: A new TCP connection/request ✔ HTTP 1.1: It allows persistent connections / chunk transfer encoding, better caching etc ✔ HTTP2: Binary protocol / multiplexing / header compression / server push etc. ✔ HTTP3: It tackles the limitations of TCP (head-of-line blocking issue) / QUIC protocol / uses UDP/ connection more secure etc

Slide 6

Slide 6 text

Polling - long polling ✔ Straightforward ✔ Universal solution ✔ No persistent connections ✔ High latency and Increased bandwidth usage can be avoided with long polling ✔ Polling is quite inefficient for real time notifications ✔ Long polling: it keeps the connection open but it can put a lot of strain on the server / can be complex and have scalability issues

Slide 7

Slide 7 text

Server-Sent Events ✔ Simple to implement ✔ HTTP based ✔ JavaScript event listener to handle these updates ✔ Automatic Reconnection ✔ Text-Based Protocol ✔ Unidirectional Communication ✔ Scalability Issues, no builtin security mechanisms

Slide 8

Slide 8 text

WebSockets ✔ A lower-level protocol than HTTP ✔ A full-duplex, bidirectional communication channel ✔ WebSockets provide a lot of control but come with some drawbacks ✔ Low Latency ✔ Support Binary and Text Data ✔ They don’t fit as neatly with HTTP/2 and HTTP/3 ✔ Complexity ✔ Scalability Challenges ✔ Security Concerns: Authorization/Authentication, DoS attacks, tunnelling, sniffing attacks etc…

Slide 9

Slide 9 text

WebSub - Braid - PREP ✔ WebSub: lets servers subscribe to updates via webhooks. It’s limited to server-to-server communication only ✔ As Proposals and not fully implemented ✔ Braid: to handle real-time updates and synchronization of data across various clients. ✔ PREP: to provide a streamlined method for pushing updates from a server to clients, making it easier to implement real-time notifications and updates.

Slide 10

Slide 10 text

Mercure ✔ No extra setup needed ✔ Compatible with Any Server ✔ Automatic Reconnects and Syncs ✔ Secure with JWT ✔ High Performance ✔ GraphQL and Hypermedia-Friendly ✔ Built-in Encryption ✔ Backward Compatibility

Slide 11

Slide 11 text

Mercure Optional Hub

Slide 12

Slide 12 text

02 -Real-time notifications with Mercure via a use case scenario

Slide 13

Slide 13 text

Use case with API Platform and Symfony ✔ Online casino platform ✔ Potential forbidden actions by users: fraud, connection from restricted countries etc ✔ System monitoring players activities: real time notifications are needed ✔ Admin dashboard is built with PHP Symfony and uses API Platform for their API

Slide 14

Slide 14 text

Setting up Mercure ✔ Via API Platform distribution ✔ Via Mercure Bundle using Symfony ✔ Composer require mercure ✔ Can install a Hub via docker

Slide 15

Slide 15 text

MercureBundle configuration ✔ Direct value / Provider / factory ✔ If none => Default LcobuccyFactory class ✔ If factory used (or default) ✔ Internally, FactoryTokenProvider will take into account the « subscribe » and « publish » claims

Slide 16

Slide 16 text

Mercure: debugging Tool Debugging tool

Slide 17

Slide 17 text

SuspiciousActivities endpoints

Slide 18

Slide 18 text

SuspiciousActivities endpoints

Slide 19

Slide 19 text

Publishing: Mercure options ✔ Topic: A list of topics/topics selectors for the update. the resource’s IRI is used as the default topic ✔ Data: This is the content of the update. The serialized form of the resource is used as the default ✔ ID: The SSE ID for this event. If not set, the Mercure Hub will generate an ID ✔ Type: The type of the SSE event. If not specified, this field is omitted ✔ Retry: The retry policy for SSE. If not defined, this field is omitted ✔ Normalization Context: The context to use for normalizing the update

Slide 20

Slide 20 text

Mercure Topics ✔ Static topic ✔ Dynamic Topic ✔ Via expression language in Symfony e.g/ placeholder/selectors ✔ Relation based topic ✔ Restrictive Updates via dynamic topics ✔ Allow subscribers to receive updates only for activities they’re allowed to see ✔ Useful in an online casino to notify specific users, such as security coordinators or managers, based on their roles or group affiliations ✔ It keeps sensitive information appropriately targeted ✔ S@=iri(object) ✔ @=iri(object.getCoordinator()) ~ "/? topic=" ~ escape(iri(object)) ✔ @=iri(object, ‘.UrlGeneratorInterface::ABS_PATH.) ✔ https://example.com/users/foo/{? topic} ✔ https://example.com/activities/* ✔ https://example.com/activities/{id} Examples It might evolve in v1

Slide 21

Slide 21 text

Mercure: restrictive update ✔ We only want to publish to a specific subscriber ✔ Publisher configuration as shown opposite ✔ Subscriber’s claim for their JWT token: https://mysite/api/users/3/ {?topic} e.g ✔ Modular and secure system

Slide 22

Slide 22 text

Mercure Topics Publisher Update with canonical and restrictive topics Subscriber With canonical topic Subscriber With restrictive update Subscriber Hub

Slide 23

Slide 23 text

Mercure: Publishing mechanism API Call Resource with ApiResource attribute and mercure option PublishMercureUpdatesListener Flush PostFlush - Verify options - Set ‘enable_async_upd ate: true’ if not specified -Build Update Class with iri, data, private, id, type, retry options as params Dispatch it through the bus with Messenger or directly publish to the hub Depending of ‘enable_async _update Via UpdateHandler synchronously or asynchronously Post HTTP request + JWT according to the claims Hub Publish to subscribers

Slide 24

Slide 24 text

Mercure: Publishing mechanism ✔ Enable_async_update: it can boost performance and it keeps the main processes of the application running smoothly, which is super important in a very high-traffic environment ✔ Scalability: the system can better manage traffic spikes, like during peak gaming events or multiple activities that need to be reported

Slide 25

Slide 25 text

Subscriber Publisher Hub SUBSCRIBE PUBLISH TOPICS Subscriber claims in JWT if private update Publisher claims in JWT NB: important to overlap, at least in part

Slide 26

Slide 26 text

Subscriber Publisher Hub SUBSCRIBE PUBLISH TOPICS Subscriber claims in JWT if private update Publisher claims in JWT IT WON’T WORK Or none or [] Or none or [] It won’t receive anything 401 received when the Hub tries to publish

Slide 27

Slide 27 text

And what about another approach?

Slide 28

Slide 28 text

Let’s trigger Messenger before Mercure Update ✔ Activities detection, especially fraud detection, often involves complex calculations or interactions with external systems ✔ Can be resource-intensive and could slow down the whole system

Slide 29

Slide 29 text

API Call Messenger Process Transport Handler - Heavy calculations - external Api calls etc - Construct Update w/ Update::class Hub Call Publish() method of the Hub::class Publish to subscribers

Slide 30

Slide 30 text

Publishing mechanism

Slide 31

Slide 31 text

Publishing mechanism

Slide 32

Slide 32 text

Could the messages be handled Concurrently?

Slide 33

Slide 33 text

Concurrent handling of messages

Slide 34

Slide 34 text

Concurrent handling of messages

Slide 35

Slide 35 text

Concurrent handling of messages

Slide 36

Slide 36 text

Concurrent handling of messages ✔ It would be possible to define how many processes should be batched and run concurrently before acknowledging them ✔ For better perf: use ext-parallel extension which depends on ZTS ✔ With FrankenPHP: ZTS is already enabled and parallel has recently become compatible with FrankenPHP ✔ In the child process, a container is cached ✔ Operations are performed concurrently for x number of processes ✔ Target ParallelMessageBus with BusNameStamp(‘parallel_bus’) ✔ php bin/console messenger:consume async_activities -p 20 ✔ Can be 5x times faster and less blocking if heavy operations are needed by some handlers This part might evolve

Slide 37

Slide 37 text

Subscriber Side

Slide 38

Slide 38 text

Discovering the hub ✔ ApiResource with mercure option: ✔ Link onto all the responses for that resource class ✔ Symfony: ✔ Discovery Helper Class

Slide 39

Slide 39 text

Subscribing

Slide 40

Slide 40 text

mercure() twig function Can be an array WithCredentials if private update

Slide 41

Slide 41 text

Set up the HubUrl with Topic(s) If lastEventId is defined, it adds: lastEventID as a query parameter If claims mentioned Authorization via cookie « mercureAuthorization » TokenFactory needed Payload JWT mercure() twig function: private

Slide 42

Slide 42 text

Last-Event-ID ✔ If connection drops: it tries to reconnect automatically ✔ Special header: Last-Event-ID ✔ Possible to define it in ApiResource Mercure option / or the hub will create it ✔ A way to get all the missed updates

Slide 43

Slide 43 text

Subscribing Authorization ✔ Via an authorization HTTP header ✔ The go-to method if the subscriber is not a web browser ✔ Via a cookie ✔ Preferred to name it mercureAuthorization ✔ Via an authorization URI query parameter ✔ Authorization= ✔ Should have no store option and private option ✔ Only if nothing else works ✔ JWS should be short lived ✔ With Symfony: possible to set the authorization cookie directly in your code/ controller ✔ Authorization::class setCookie() ✔ Make sure to not define it twice!

Slide 44

Slide 44 text

Discover the Hub and subscribe efficiently ✔ @api-platform/mercure: A super handy eventSource wrapper with a mercure function ✔ Discover a mercureHub : fetch + new EventSource ✔ Very useful and it avoids multiple subscriptions with multiple connexions ✔ It manages multiple topics on a single connection ✔ It manages opening and closing of eventSource when updating the topics

Slide 45

Slide 45 text

API for active subscriptions ✔ It sends updates whenever a subscription is created or closed. This is crucial for real-time systems like online casinos, where monitoring active sessions is important ✔ /subscriptions: Lists all subscriptions ✔ /subscriptions/{topic}: Shows subscriptions for a specific topic ✔ /subscriptions/{topic}/{subscriber}: Gives details for a specific subscription ✔ The mercure claim of the JWT can also contain user-defined values under the payload key: a convenient way to share data related to one subscriber to other subscribers It might evolve in v1

Slide 46

Slide 46 text

Mercure ✔ A robust solution for real time communication ✔ Easy to deliver instant notifications ✔ A key protocol for meeting real-time communication demands ✔ Efficient across a variety of different platforms and environments ✔ Laravel community: some exciting developments are on the way for the server and client integration

Slide 47

Slide 47 text

Thank you! Thank you! Any questions?