Rails 7 додаток готовий до продакшн середовища з підтримкою WebSocket для TurboBroadcast

Як використовувати solid-cable для Turbo Broadcast

1. Додайте гем solid-cable до вашого Gemfile:

gem 'solid-cable'

Потім виконайте команду:

bundle install

Згенеруйте міграцію для зберігання повідомлень solid-cable-message в db/migrate/20241217100954createsolidcablemessages_table.rb. Тут я додав таблицю solid cable до тієї бази даних, яку ми вже використовуємо.

class CreateSolidCableMessagesTable < ActiveRecord::Migration[7.2]  
 def change  
 create_table :solid_cable_messages do |t|  
 t.binary :channel, limit: 1024, null: false  
 t.binary :payload, limit: 536_870_912, null: false  
 t.datetime :created_at, null: false  
 t.bigint :channel_hash, null: false  

 t.index :channel, name: "index_solid_cable_messages_on_channel"  
 t.index :channel_hash, name: "index_solid_cable_messages_on_channel_hash"  
 t.index :created_at, name: "index_solid_cable_messages_on_created_at"  
 end  
 end  
end

Оновіть конфігураційні файли Rails:

Замість стандартної конфігурації Action Cable використовуйте solid-cable.

Приклад: config/cable.yml виглядатиме наступним чином:

development:  
 adapter: solid_cable  
 channel_prefix: rails_4_4sa_development  
 polling_interval: 0.1.seconds  
 message_retention: 1.day  

test:  
 adapter: solid_cable  
 channel_prefix: rails_4_4sa_test_cable  

production:  
 adapter: solid_cable  
 channel_prefix: <%= ENV['MYSQL_DATABASE'] %>  
 polling_interval: 0.1.seconds  
 message_retention: 1.day

У файлі routes.rb

Rails.application.routes.draw do  
 mount ActionCable.server => '/cable'  
end

У файлі config/database.yml

default: &default  
 adapter: mysql2  
 encoding: utf8mb4  
 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>  
 username: root  

development:  
 <<: *default  
 database: rails_4_4sa_development  

production:  
 <<: *default  
 username: <%= ENV['MYSQL_USERNAME'] %>  
 password: <%= ENV['MYSQL_PASSWORD'] %>  
 database: <%= ENV['MYSQL_DATABASE'] %>  
 host: <%= ENV['MYSQL_ADDRESS'] %>  
 strict: false  
 sslmode: 'verify-full'  
 sslrootcert: /app/rdscerts/rds-combined-ca-bundle.pem  
 sslca: /app/rdscerts/rds-combined-ca-bundle.pem

Налаштуйте трансляції Turbo Streams:

Turbo Streams використовують Action Cable для передачі оновлень у реальному часі до клієнтів. З solid-cable цей процес залишається незмінним.

Приклад: трансляція оновлень у Rails:

# У вашому контролері Rails, моделі або worker/job  
Turbo::StreamsChannel.broadcast_replace_to(  
 "posts",  
 target: "post_#{post.id}",  
 partial: "posts/post",  
 locals: { post: post }  
)
    <%= render partial: "post", locals: { post: post } %>   

З усіма вищезгаданими кроками додаток Rails працює у розробці. Тепер давайте розглянемо налаштування для продакшн середовища. Почнемо з Що таке upstream сервер? Наприклад, у типовому налаштуванні Ruby on Rails:
- Клієнт: Браузер або будь-який HTTP клієнт робить запит до сервера Nginx.
- Nginx: Виконує роль зворотного проксі. Він перенаправляє запит до upstream сервера.
- Upstream сервер: У вашому випадку, ймовірно, сервер Puma, який обробляє запит і генерує відповідь.

Як Nginx визначає upstream сервери

У конфігурації Nginx upstream сервери визначаються за допомогою директиви upstream, часто в налаштуваннях балансування навантаження.

Приклад:

upstream puma {  
 server 127.0.0.1:3000; # Puma сервер на localhost, порт 3000   
}  

Тут:
- puma — це назва групи upstream серверів.
- 127.0.0.1:3000 — це реальна адреса та порт, на якому працює Puma.

Чому використовувати Nginx як проксі до upstream серверів?

  1. Балансування навантаження: Nginx може розподіляти запити між кількома upstream серверами.
  2. Безпека: Nginx може обробляти завершення HTTPS, захищаючи upstream сервер.
    3.
    Продуктивність: Nginx може кешувати статичні ресурси і зменшити навантаження на upstream сервер.
  3. Підтримка WebSocket: Як у вашому прикладі, Nginx може полегшити з’єднання WebSocket з upstream сервером.

У вашій конкретній конфігурації upstream сервером є сервер Puma, який обробляє ваше Rails додаток.

Нижче наведена конфігурація Nginx для увімкнення ActionCable у продакшн сервері Nginx. Ви можете додати нижченаведену конфігурацію Nginx, і ваше додаток буде готове до роботи.

location /cable {  
 proxy_pass http://puma/cable;  
 proxy_http_version 1.1;  
 proxy_set_header Upgrade $http_upgrade;  
 proxy_set_header Connection "upgrade";  
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
 proxy_set_header Host $http_host;  
 proxy_redirect off;  
 proxy_set_header X-Real-IP $remote_addr;  
 proxy_set_header X-Forwarded-Proto $scheme;  

 # Збільшуємо таймаут для довготривалих з’єднань WebSocket  
 proxy_read_timeout 3600s;  
 proxy_send_timeout 3600s;  
}

Розберемо, що робить кожен рядок у блоці location /cable:

1. location /cable {

Визначає блок локації в конфігурації Nginx, який обробляє запити до /cable, зазвичай використовуваний для WebSocket з’єднань у Ruby on Rails додатку з використанням Action Cable.

2. proxy_pass http://puma/cable;

Перенаправляє вхідні запити до upstream сервера (в цьому випадку, сервер Puma) на вказаний кінцевий шлях /cable.

  • puma ймовірно визначений як upstream сервер у конфігурації Nginx.

3. proxy_http_version 1.1;

Гарантує, що Nginx використовує HTTP/1.1 для проксованих запитів. Це необхідно для WebSocket з’єднань, оскільки HTTP/1.1 підтримує заголовок Upgrade, який потрібен для WebSocket.

4. proxy_set_header Upgrade $http_upgrade;

Встановлює заголовок Upgrade у запиті зі значенням $http_upgrade, яке Nginx автоматично визначає з вхідного WebSocket запиту.

  • Цей заголовок вказує на перехід протоколу з HTTP на WebSocket.

5. proxy_set_header Connection "upgrade";

Встановлює заголовок Connection в значення upgrade. Це гарантує, що буде запитано оновлення протоколу WebSocket при проксуванні запиту.

6. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Додає оригінальну IP адресу клієнта до заголовка X-Forwarded-For.

  • Це допомагає upstream серверу ідентифікувати фактичну IP адресу клієнта, навіть коли запити проходять через кілька проксі.

7. proxy_set_header Host $http_host;

Встановлює заголовок Host в значення заголовка Host вхідного запиту.

  • Це гарантує, що upstream сервер побачить правильну інформацію про хост.

8. proxy_redirect off;

Відключає автоматичне переписування URL в редиректах, що надходять від upstream сервера.

  • Це корисно для збереження оригінальної структури URL.

9. proxy_set_header X-Real-IP $remote_addr;

Додає реальну IP адресу клієнта в заголовок X-Real-IP.

  • Ще один спосіб передати IP клієнта на upstream сервер.

10. proxy_set_header X-Forwarded-Proto $scheme;

Встановлює заголовок X-Forwarded-Proto в схему (http або https), яку використовував клієнт.

  • Це допомагає upstream серверу визначити, чи був оригінальний запит зроблений через HTTP чи HTTPS.

11. proxy_read_timeout 3600s;

Це опціонально. Встановлює максимальний час, який Nginx чекає на відповідь від upstream сервера, перш ніж закрити з’єднання.

  • Значення 3600s (1 година) високе, щоб підтримувати довготривалі з’єднання WebSocket.

12. proxy_send_timeout 3600s;

Це опціонально. Встановлює максимальний час, який Nginx чекає на передачу даних від клієнта, перш ніж закрити з’єднання.

  • Також встановлено на 1 годину для підтримки довготривалих з’єднань WebSocket.

Перекладено з: Rails7 app production ready with WebSocket for TurboBroadcast

Leave a Reply

Your email address will not be published. Required fields are marked *