Aujourd'hui vous allez apprendre comment éviter ce qu'on appelle les "goulots d'étranglement" ou en d'autres termes, comment permettre à votre application de gérer un plus gros trafic en évitant d'augmenter la taille de votre serveur.
Chez Capsens, la concurrence a longtemps Ă©tĂ© un sujet d'ombre. AprĂšs avoir testĂ©, cassĂ© et s'ĂȘtre amĂ©liorĂ© encore et encore, nous sommes aujourd'hui fiers de pouvoir vous partager notre modeste expertise sur le sujet. C'est IsmaĂ«l qui vous en parlera et pour le fun Johnny Hallyday nous servira d'exemple.
Au programme :
Ăviter les goulots d'Ă©tranglement avec Sidekiq par Ismael
Le problĂšme du lock PostgreSQL
Tests unitaires de la concurrence
Passage en asynchrone avec Sidekiq
Synchroniser le front-end
Le job de tes rĂȘves !
Le défi (avec la réponse farfelue d'Antoine)
Bonjour et bienvenue sur la 10Úme édition de Ruby Biscuit.
Vous ĂȘtes maintenant 202 abonnĂ©s đ„ł Si vous nâĂȘtes pas dĂ©jĂ inscrit :
Ăviter les goulots d'Ă©tranglement avec Sidekiq
Il arrive que l'on soit confrontĂ© Ă des situations qui impliquent un nombre de places limitĂ©es et oĂč l'ordre est important. Dans la vie privĂ©e, nous appelons cela un shotgun mais pour cet article le terme FIFO (First In First Out) sera plus adaptĂ©.
Prenons un exemple concret :
Le dernier concert post mortem de Johnny Hallyday en petit comité est annoncé.
Il n'y a que 100 places et elles seront en vente le 31 janvier Ă 17h00 .
Grùce à une campagne marketing étonnante, l'événement fait le buzz.
Dans ce genre de cas, on se retrouve face à un problÚme de taille. En effet, nous savons que le trafic sur la plateforme sera trÚs élevé le 31 janvier aux environs de 17h00 et que de nombreux utilisateurs tenteront de ravir ces places convoitées. Le souci est que seuls 100 d'entre eux y parviendront, traiter les demandes dans l'ordre chronologique est donc crucial.

Le problĂšme du lock PostgreSQL
Une solution qui nous viendrait Ă l'esprit pourrait ĂȘtre d'avoir recours Ă un lock PostgreSQL pour Ă©liminer les problĂšmes de concurrences, afin de s'assurer qu'on ne peut pas accepter deux souscriptions simultanĂ©ment car il ne faut absolument pas qu'il soit possible de vendre plus de tickets que de places disponibles.
Dans le scĂ©nario ci-dessus, le lock PostgreSQL permet de s'assurer que les souscriptions sont bien traitĂ©es une par une. Si une requĂȘte est dĂ©jĂ passĂ©e dans le lock, alors la suivante doit attendre que le lock soit levĂ© et ainsi de suite. Le ticket dispose aussi de validations afin de vĂ©rifier qu'il reste assez de place pour lui dans l'Ă©vĂšnement.
Ce genre de systĂšme implique que le temps de traitement de chaque requĂȘte devient donc proportionnel au nombre de requĂȘtes avant lui. En prenant un temps moyen raisonnable de 0.25 seconde de temps de traitement par requĂȘte, on peut aisĂ©ment deviner qu'Ă partir de 60 requĂȘtes en simultanĂ©e, on atteint les 15 secondes soit une expĂ©rience utilisateur plutĂŽt mĂ©diocre voire un timeout selon comment est configurĂ© votre serveur web.
Par souci de simplification, j'élude volontairement de nombreux autres problÚmes que pose ce phénomÚne notamment le fait que cela implique de rapidement atteindre le nombre de threads total disponibles dans votre application : cela n'impacte donc plus uniquement ce formulaire mais toute votre application.
Tests unitaires de la concurrence
Reproduisons le scénario avec un test unitaire (rspec) :
Sans surprise, le dernier test Ă©choue : chaque requĂȘte durant 0.25 secondes, 3 requĂȘtes concurrentes prennent au minimum 0.75 seconde.
Passage en asynchrone avec Sidekiq
Une solution que nous adoptons réguliÚrement chez Capsens est de supprimer le lock et d'accepter toutes les demandes sans vérifier qu'il n'y a pas de souci de concurrence.
Les demandes sont considérées comme "en attente de traitement" puis on déclenche un job Sidekiq unique dont le travail sera de traiter toutes les demandes en attente de traitement dans leur ordre de création en base de données. La logique FIFO est donc conservée et le job étant unique, on est sûr de ne pas avoir de souci de concurrence ni de bloquer un nombre croissant de threads.
Voyons ceci dans la pratique.
On modifie le controller pour ne plus avoir de lock et appeler un job Sidekiq :
Notez que mĂȘme si on ne se soucie plus de la concurrence, on peut tout de mĂȘme ajouter une vĂ©rification afin de ne pas accepter plus de X tickets que le maximum de place. Rien ne sert de prendre 1000 participants si nous n'offrez que 100 places. En plus de faire espĂ©rer pour rien nos fans, cela ferait travailler le serveur inutilement.
On implémente ensuite notre Events::ProcessPendingTicketsJob.
Le job utilise un lock Redis (grĂące Ă la gem RedLockRb) afin de s'assurer de bien ĂȘtre toujours unique, c'est-Ă -dire qu'il ne puisse pas traiter des tickets pour un mĂȘme Ă©vĂšnement sur 2 threads en parallĂšle afin de prĂ©server la logique FIFO :
Le job commence par tenter de déposer un lock Redis, s'il y a en déjà un, il se coupe.
Pour chaque ticket non traité de l'évÚnement, il le marque comme traité (afin qu'il ne soit plus traité par la suite) et le valide si l'évÚnement a encore de la place.
Note : on utilise un bang (!) pour s'assurer qu'en cas d'erreur, le job échoue et que l'utilisateur ne perde pas sa place à cause d'une erreur technique. Si un ticket échoue, tous les suivants doivent échouer.Le job se relance plus tard si de nouveaux tickets ont été crées pendant qu'il tournait
Le job retire le lock Redis
On met Ă jour le test de requĂȘte en consĂ©quence (on en profite pour multiplier par 10 la concurrence au passage đ) :
On lance les tests :
Synchroniser le front-end
Bien entendu, pour avoir un parcours utilisateur complet, il faut implémenter un systÚme pour faire patienter l'utilisateur dans une file d'attente en l'informant que sa demande est en cours de traitement.
Plusieurs solutions sont possibles pour tenir cette file d'attente synchronisée avec le serveur:
đđŒ Lui envoyer un mail lorsque c'est terminĂ©
â Faire du Short Polling en faisant une requĂȘte Ajax toutes les X secondes afin de demander au serveur si le ticket a Ă©tĂ© traitĂ©
đ„ Utiliser ActionCable (websocket) pour permettre au serveur de notifier le client directement lorsque son ticket est traitĂ© (la solution adoptĂ©e chez Capsens en gĂ©nĂ©ral)
Ce genre de systÚme vous permet aussi trÚs facilement de garder les utilisateurs déçus en liste d'attente afin de pouvoir les re-inscrire en cas de désistement et donc maximiser vos chances que Johnny Hallyday ait bien 100 participants à son concert !
Le job de tes rĂȘves !
Comme vous le savez, derriĂšre Ruby Biscuit, il y a Capsens đ , nous sommes une agence web spĂ©cialisĂ©e dans le Ruby on Rails depuis 10 ans.
Avec le temps on s'est rendu compte que beaucoup de dévs choisissent leur entreprise un peu par hasard alors qu'ils pourraient mieux s'épanouir et se valoriser dans des structures qui leur correspondent bien.
Ce qui tombe super bien c'est que chez Capsens nous avons une excellente connaissance de l'écosystÚme Ruby on Rails en France, avec un réseau d'entreprises considérable.
C'est pourquoi on vous annonce Ă travers cette newsletter que nous mettons Ă profit notre connaissance du mĂ©tier pour vous aider Ă trouver le poste de vos rĂȘves !
ConcrĂštement :
Tu souhaites trouver le job de tes rĂȘves ? Alors rĂ©ponds Ă cet email ! Tu peux dire "Coucou", ça suffit !
On te proposera aussitÎt des créneaux pour une visio afin de faire connaissance
Puis nous te proposerons 3 entreprises qui correspondent Ă qui tu es. Et pour chacun de ces postes :
Tu pourras discuter avec un dĂ©veloppeur de l'Ă©quipe (pas le recruteur lui-mĂȘme) afin de savoir comment ça se passe de l'intĂ©rieur. No bullshit
Un développeur de Capsens t'aidera à :
Analyser le poste : ce qui a l'air bien, les dangers, quelles conditions poser pour que tout se passe bien
Te préparer pour que tu décroches le bon poste
Tu veux aller vers une vie professionnelle plus Ă©panouie ? đ Eh bien, on attend ton
e-mail ! Et si tu aimes dĂ©jĂ ton travail, ne nous contacte surtout pas ! Ou alors fais-le pour nous recommander ta boite đ
Le Défi
Le défi de la derniÚre newsletter n'était pas des moindres !
Pour rappel, la consigne était la suivante :
Ăcris âRuby Biscuitâ sans utiliser de Literals : pas de strings, de nombres, symboles, regex etc.
đïž Antoine vous partage sa rĂ©flexion pour rĂ©ponse Ă ce dĂ©fi, accrochez-vous bien :
Donc quâest-ce quâon peut faire sans litterals et comment on peut construire une string ?
On peut avoir nil avec une variable dâinstance @foo non initialisĂ©e.
to_i nous permet dâavoir 0, puis succ les integers de notre choix :
@foo.to_i => 0
@foo.to_i.succ => 1
On peut convertir un integer en string avec to_s bien sûr, mais aussi avec Integer#chr qui retourne le caractÚre représenté par celui-ci.
Et vice versa avec String#ord, qui retourne lâinteger reprĂ©sentant le caractĂšre :
âAâ.ord => 65
66.chr => âBâ
On pourrait donc faire @foo.to_i.succ.succ.succ.succâŠ.chr + foo.to_i.succ.succâŠ. etc. pour construire notre String caractĂšre par caractĂšre.
Mais on est en Ruby, on peut aussi tricher avec les constantes.
Pourquoi se casse la tĂȘte ? En dĂ©finissant une classe Biscuit, ont peut faire Biscuit.to_s pour avoir âBiscuitâ !
Ou encore plus concis, définir une méthode qui retourne le symbole représentant cette méthode.
Ainsi def Biscuit;Â end.to_s retourne âBiscuitâ.
Finalement, le seul caractĂšre qui nâest pas trivial est lâespace â â.
â â.ord => 32. Bon on va quand mĂȘme pas faire 32 .succ dâaffilĂ©, on doit pouvoir lâavoir plus efficacement.
On peut avoir cette valeur en faisant la valeur dâun caractĂšre moins celle dâun autre. Par exemple :
âAâ.ord => 65
âaâ.ord => 97
donc (âaâ.ord - âAâ.ord).chr => â â
Avec tout ça, une solution lisible peut ĂȘtre :
Et en la condensant le plus possible :

Merci Antoine ! đ„Č
Voici les rÚgles du prochain défi :
Calculer le triangle de Pascal jusqu'à un nombre donné de lignes.
Dans le triangle de Pascal, chaque nombre est calculé en additionnant les nombres à droite et à gauche de la position actuelle dans la ligne précédente.
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
# ... etc
Tout comme les derniÚres fois, envoyez-moi vos réponses en répondant à cette newsletter et je publierai la meilleure dans la prochaine édition !
Si tu es arrivé jusqu'ici tu as deux options :
soit tu n'es pas encore abonné et c'est alors le moment
soit tu l'es dĂ©jĂ et dans ce cas je compte sur toi pour partager cette Ă©dition đ
IsmaĂ«l, Antoine et MĂ©lanie đ
Et merci Stan pour la relecture !











Je ne suis pas objectif, mais : Mon Dieu que cette newsletter est quali đ