perf(server): add synchronous HTTP request path - #33
Conversation
Benchmark d’intégration — toutes les optimisations HTTPJ’ai assemblé localement, sans pousser de branche d’intégration, les têtes de Méthode : même orb et même suite que le baseline initial, Node 24.19, serveur CPU 2, autocannon CPU 4/6, 3 répétitions, chauffe 2 s + mesure 5 s, ordre randomisé. Tous les runs retenus ont 0 erreur, 0 timeout et 0 non-2xx.
Comparaison dans le même run final :
Conclusion honnête : le cumul apporte un gros saut et dépasse Adonis dans plusieurs cas, mais ne dépasse pas encore Nest/Fastify hors POST. Par rapport à l’intégration précédente |
Co-authored-by: Upd4ting <upd4ting@gmail.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a019cf-61b5-7205-bae9-cce46f10f7dc
Amp-Thread-ID: https://ampcode.com/threads/T-01a019cf-61b5-7205-bae9-cce46f10f7dc Co-authored-by: Upd4ting <upd4ting@gmail.com>
f6b4e73 to
0088869
Compare
Résumé
prefix → handler → postfix → monitor → senddans la même pile lorsque toutes les étapes sont synchrones ;db7869f, donc évaluée avec les optimisations perf(api): compile request controller resolution #29–perf(router): compile dynamic parameter extraction #32 sans les dupliquer dans le diff de cette PR.Diff incrémental contre le nouveau
main: 2 fichiers, 617 ajouts, 75 suppressions (src/server.tset la suite ciblée). Head :0088869.Cause mesurée
Le profil
async_hooksa été rejoué après rebase sur 50 000 GET passant par les contrôleurs compilés, avec prefix, postfix et monitor synchrones :db7869f(perf(api): compile request controller resolution #29–perf(router): compile dynamic parameter extraction #32) : 750 000 Promises, 15/requête ;0088869(perf(api): compile request controller resolution #29–perf(server): add synchronous HTTP request path #33) : 0 Promise, 0/requête.Le profil CPU initial de ce même listener sous charge montrait aussi
runMicrotasksà 1,78 % avant contre 0,04 % après. Les microtasks imposées par lesawaitdu listener sont donc bien la cause supprimée ; aucun cas spécial fixture n'est utilisé.Benchmark HTTP après rebase
Même orb, Node 22.14.0, autocannon 8.0.0, serveur HTTP Node réel, contrôleurs compilés, résolution de paramètres, routeur,
RequestContext,HTTPResult, prefix/postfix/monitor synchrones et envoi réel. Baseline exactedb7869f(#29–#32), candidat exact0088869(#29–#33). Chauffe 1 s avant chaque mesure, mesure 3 s, 5 répétitions alternées baseline/candidat. Le POST consomme un corps JSON ; le pipeline async contient un contrôleurasyncet unawait. p99 en ms ; CV calculé sur req/s.* Le scénario erreur a produit les HTTP 500 attendus (256 458 réponses non-2xx baseline, 291 696 candidat), sans erreur réseau ni timeout.
Lecture prudente : l'orb était bruitée, avec des CV de 3,6 à 17,7 %. Les moyennes et médianes vont toutes dans le même sens, mais un run pairé sur cinq était marginalement négatif pour le pipeline sync (−0,1 %) et les 1 000 routes (−1,5 %). Il n'y a aucune régression agrégée, y compris sur le chemin comportant un handler async, mais les pourcentages précis ne doivent pas être lus comme des microbenchmarks à faible variance.
Comparaison frameworks
La campagne comparative précédente, exécutée dans cette même orb avec la même pile et cinq répétitions, plaçait le candidat pré-rebase à 37 721 req/s (GET c=10) et 37 228 (c=100), contre Adonis HTTP 7.7 à 39 978 et 38 314, Nest/Fastify à 41 106 et 41 806, et Fastify seul à 45 482 et 48 242. La nouvelle campagne rebasée mesure 38 408 et 38 292, soit au niveau de l'ancien résultat Adonis, mais ces séries n'ont pas été alternées ensemble : cette comparaison reste indicative, pas une preuve de dépassement. Le benchmark avant/après ci-dessus est la comparaison causale retenue.
Tests et validation
src/test/server-synchronous-path.test.tscouvre :thenstateful lu exactement une fois ;Validation locale après
pnpm install --frozen-lockfile:pnpm build✅pnpm lint✅pnpm test✅ — 149 testsLa review valide sur la double lecture du getter
thenreste corrigée et couverte par régression. Aucun thread de review ouvert au moment de cette mise à jour. CI post-force-push : Ubuntu ✅, GitGuardian ✅.Limites et risques
thenune seule fois et conserve les rejets/throws.void | PromiseLike<void>;requestListenern'est pas exporté par l'API publique du package et le server factory ignore déjà sa valeur de retour.async.