ENbext.dev
DocumentationIntégrations de frameworks

Traduction automatique depuis l’anglais. Consulter l’original.

Sur cette page

Intégration des rails

bext se trouve devant une application Rubis sur Rails en tant que couche périphérique. Rails conserve l'intégralité de l'expérience du framework - contrôleurs, vues, ActiveRecord, générateurs, tests - et bext ajoute les problèmes de production que chaque équipe Rails doit créer ou intégrer : terminaison TLS, HTTP/2 et HTTP/3, un pare-feu d'application Web, un cache périphérique, Prometheus + OpenTelemetry et une absorption DDoS.

Il ne s'agit pas d'un adaptateur au sens Astro / SvelteKit. Rails est un framework côté serveur complet qui fournit sa propre couche HTTP via Puma ; bext s'intègre par proxy inverse à Puma plutôt qu'en encapsulant le pipeline de rendu de Rails. Le démarreur ci-dessous est un échafaudage – un exemple fonctionnel de la forme, pas une application Rails exécutable. Vous apportez Rails ; bext le fait face.

Quand l’utiliser. Si votre équipe possède déjà un Rails application et vous souhaitez mettre bext devant pour le bord préoccupations (TLS, cache, WAF, métriques), c'est l'intégration pour toi. Si vous souhaitez créer une nouvelle application SSR non-Rails sur bext, utilisez PRISM ou l'un des framework JS adaptateurs à la place.

Architecture#

code
    ┌─────────┐          ┌───────────────────────────┐          ┌─────────────┐
    │         │  HTTPS   │            bext           │   HTTP   │    Puma     │
    │ client  │ ───────► │  TLS • WAF • cache • obs  │ ───────► │   :3000     │
    │         │  :443    │           :8080           │ 127.0.0.1│   + Rails   │
    └─────────┘          └───────────────────────────┘          └─────────────┘

Parcours d’une requête :

  1. Le client ouvre une connexion TLS à bext sur :443 (ou :8080 en développement).
  2. bext termine TLS, exécute le WAF, vérifie le cache, enregistre métriques, puis transmet la demande à Puma via HTTP/1.1 sur 127.0.0.1:3000 via le pool en amont.
  3. Rails traite la demande. La réponse revient à travers bext, qui applique la compression et la journalisation, puis au client via HTTP/2 ou HTTP/3.

Puma ne voit jamais l'Internet public. Rails n'expédie jamais de code TLS. bext n’analyse jamais ActionDispatch.

bext.config.toml#

La configuration du projet de démarrage, réduite à l’essentiel :

toml
[server]
port = 8080

# Upstream: Puma running Rails
[upstreams.rails]
strategy = "round_robin"
keepalive = 32

[[upstreams.rails.servers]]
url = "http://127.0.0.1:3000"

[upstreams.rails.health]
enabled = true
path = "/up"                 # Rails 7.1+ ships this endpoint
interval_ms = 10000

[upstreams.rails.retry]
count = 1
retry_on = ["connect_error", "502", "503"]

[[route_rules]]
pattern = "/*"
proxy = "rails"

[waf]
enabled = true

Les parties importantes :

  • [upstreams.rails] déclare le pool. Pour un seul Puma processus, une entrée [[upstreams.rails.servers]] suffit. Pour plusieurs instances Puma (déploiements sans temps d'arrêt, bleu/vert), ajoutez plus d'entrées et des round robins bext entre elles.
  • [upstreams.rails.health] exécute une sonde en arrière-plan sur Point de terminaison /up intégré de Rails. Un Puma mort est expulsé de la piscine en quelques secondes.
  • [upstreams.rails.retry] réessaye un ensemble limité d'idempotents échecs (erreurs de connexion, 502/503) une fois, avec un délai de 100 ms. Valeurs par défaut sûres : remplacez chaque projet si nécessaire.
  • [[route_rules]] envoie chaque chemin vers le rails en amont. Ajoutez des règles plus spécifiques au-dessus de celle-ci pour créer des chemins d'actifs statiques (par exemple, /assets/* servi directement à partir de bext ) ou des itinéraires natifs bext qui contournent complètement Rails.

Exécuter Puma sous systemd#

bext s'attend à ce que Puma soit opérationnel avant de commencer le transfert. En production, exécutez Puma en tant qu'unité systemd pour que le système d'exploitation le redémarre en cas de crash :

ini
# /etc/systemd/system/rails-app.service
[Unit]
Description=Puma for Rails app
After=network.target

[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/srv/app/current
Environment=RAILS_ENV=production
ExecStart=/usr/bin/env bundle exec puma -C config/puma.rb -p 3000
Restart=on-failure
RestartSec=2
StandardOutput=append:/var/log/rails-app.log
StandardError=append:/var/log/rails-app.log

[Install]
WantedBy=multi-user.target

Alors:

bash
sudo systemctl enable --now rails-app
sudo systemctl enable --now bext

L'ordre de redémarrage n'a pas d'importance dans la pratique : la sonde de santé en amont de bext trouvera Puma dès qu'elle apparaîtra.

Ce que bext ajoute#

Préoccupation Qui s'en occupe
TLS / ACME bext
HTTP/2, HTTP/3 (QUIC) bext
WAF (bots, limite de débit) bext
Cache périphérique (ISR/SWR) bext
Compression (brotli) bext
Métriques Prometheus bext
Traces OpenTelemetry bext
Service d'actifs statiques Soit (voir ci-dessous)
Logique métier Rails
ActiveRecord/DB Rails
Travaux en arrière-plan Rails (Sidekiq, Solid Queue, etc.)
Pipeline d’actifs Rails / Arbre de transmission / Pignons

Actifs statiques#

Par défaut, le démarreur transmet tout à Puma, donc celui de Rails Le répertoire public/ est servi par Rails. Pour de meilleures performances de pointe, servez public/ directement depuis bext :

toml
[[route_rules]]
pattern = "/assets/*"
render = "static"
# bext will look for files under `public/assets/` relative to app_dir.

[[route_rules]]
pattern = "/packs/*"     # or /packs-test/* if using webpacker
render = "static"

[[route_rules]]
pattern = "/*"
proxy = "rails"

Avec ces règles, bext sert des ensembles d'actifs hachés avec des en-têtes de cache immuables ; Puma ne voit que le trafic dynamique.

Invalidation du cache#

Le cache périphérique de bext est désactivé par défaut pour les routes proxy - les réponses Rails définissent déjà les en-têtes Cache-Control appropriés et bext les respecte. Pour mettre en cache une réponse Rails en périphérie, définissez un Cache-Control: public, max-age=... dans le contrôleur et ajoutez une entrée [[route_rules]] correspondante avec cache = true.

Pour invalider le cache depuis Rails, appelez l'API de purge basée sur les balises de bext :

ruby
# app/services/bext_cache.rb
require "net/http"
require "json"
class BextCache
  def self.invalidate(tag)
    uri = URI("http://127.0.0.1:8080/__bext/cache/purge")
    Net::HTTP.post(uri, { keys: [tag] }.to_json, "Content-Type" => "application/json")
  end
end

Désormais, BextCache.invalidate("products") efface chaque entrée de cache marquée products sur le périmètre bext.

Détection#

Le scanner importation infrarouge de bext reconnaît un projet Rails à partir de :

  • un Gemfile qui déclare gem "rails", et
  • un fichier config.ru

Lorsque les deux sont présents, bext infra import suggère le modèle d'intégration Rails et propose d'échafauder à partir de @bext/starter-rails.

L'entrée de catalogue réside dans crates/bext-import/catalog/frameworks.yaml :

yaml
- match:
    any_of_files:
      - "Gemfile"
      - "config.ru"
    gemfile:
      any_of_gems:
        - "rails"
  extract:
    framework: rails
    starter: "@bext/starter-rails"
  confidence: high

Le démarreur#

bash
bext new my-rails-app --template @bext/starter-rails
cd my-rails-app
bundle install
bin/rails server -p 3000     # one terminal
bext serve                    # another

Visitez http://localhost:8080.

Le démarreur est , un échafaudage, pas une application Rails fonctionnelle. Il est livré avec la forme minimale dont bext a besoin : un Gemfile, un config.ru, un config/routes.rb, un petit contrôleur home#index et une vue ERB, ainsi que la plomberie bext.config.toml câblée. Utilisez rails new pour générer un véritable projet Rails et supprimez le démarreur bext.config.toml dedans - c'est le flux de travail canonique.

Conseil

Si votre équipe migre depuis une installation nginx + Puma existante, consultez À partir de nginx : le mode de compatibilité nginx de bext peut lire directement votre nginx.conf existant, ce qui permet une première migration sans réécriture.

Comparaison avec nginx + Puma#

Si vous utilisez actuellement nginx devant Puma, la migration est mécanique :

code
nginx.conf                          bext.config.toml
─────────                           ────────────────
upstream rails { server … }   ───►  [upstreams.rails.servers] url = …
proxy_pass http://rails;      ───►  [[route_rules]] proxy = "rails"
listen 443 ssl;               ───►  [tls] (auto ACME)
ssl_certificate …;            ───►  [tls.acme] domains = […]
limit_req_zone …;             ───►  [waf.rate_limit]

Le Mode de compatibilité nginx de bext peut même lire votre nginx.conf existant et l’exécuter directement : aucune migration nécessaire pour cette première étape.

Limites#

  • Les extensions bext ne peuvent pas encore modifier les requêtes. Les extensions bext peuvent s’exécuter lors des requêtes et des réponses, mais le chemin de proxy inverse n’expose pas encore toutes les possibilités offertes aux routes SSR. L’intégration des extensions aux routes passant par le proxy arrivera avec la fonctionnalité Router dans E11.
  • Pas de multiplexage WebSocket. bext transmet actuellement WebSockets au serveur en amont, mais ne partage pas encore de pool de connexions pour ces échanges. Les applications Action Cable à forte diffusion devraient suivre les prochains travaux sur bext-realtime.
  • Pas d’environnement d’exécution Ruby intégré. Contrairement à l’intégration PHP qui embarque libphp via une SAPI personnalisée, bext n’intègre pas de machine virtuelle Ruby. Rails s’exécute dans son propre processus Puma. Ce choix convient à Rails : son équipe fournit Puma, bundler et l’ensemble des outils ; placer bext devant eux via HTTP conserve toutes les facilités de développement offertes en amont.

En rapport#

Modifier cette page ↗Besoin d’aide ? ↗
Rechercher dans la documentation

Saisissez un sujet, une commande ou une question.