介绍
在开发 Ruby on Rails 应用程序时,您可能会发现您的应用程序任务应该异步执行。 处理数据、发送批量电子邮件或与外部 API 交互都是可以使用 后台作业 异步完成的工作示例。 使用后台作业可以通过将潜在的时间密集型任务卸载到后台处理队列来提高应用程序的性能,从而释放原始请求/响应周期。
Sidekiq 是您可以在 Rails 应用程序中实现的更广泛使用的后台作业框架之一。 它由 Redis 提供支持,这是一种以灵活性和性能着称的内存键值存储。 Sidekiq 使用 Redis 作为作业管理存储,每秒处理 数千个作业 。
在本教程中,您将把 Redis 和 Sidekiq 添加到现有的 Rails 应用程序中。 您将创建一组 Sidekiq 工作程序类和方法来处理:
- 将濒危鲨鱼信息从项目存储库中的 CSV 文件批量上传到应用程序数据库。
- 删除此数据。
完成后,您将拥有一个演示应用程序,该应用程序使用工作人员和作业来异步处理任务。 这将成为您将工作人员和工作添加到您自己的应用程序的良好基础,使用本教程作为起点。
先决条件
要遵循本教程,您将需要:
- 运行 Ubuntu 18.04 的本地机器或开发服务器。 您的开发机器应该有一个具有管理权限的非 root 用户和一个配置了
ufw
的防火墙。 有关如何设置的说明,请参阅我们的 Initial Server Setup with Ubuntu 18.04 教程。 - Node.js 和 npm 安装在本地机器或开发服务器上。 本教程使用 Node.js 版本 10.17.0 和 npm 版本 6.11.3。 有关在 Ubuntu 18.04 上安装 Node.js 和 npm 的指导,请按照 如何在 Ubuntu 18.04 上安装 Node.js 的 “使用 PPA 安装” 部分中的说明进行操作。
- 安装在本地机器或开发服务器上的 Yarn 包管理器。 您可以按照官方文档中的安装说明。
- Ruby、rbenv 和 Rails 安装在本地计算机或开发服务器上,遵循 如何在 Ubuntu 18.04 上使用 rbenv 安装 Ruby on Rails 中的 Steps 1-4 . 本教程使用 Ruby 2.5.1、rbenv 1.1.2 和 Rails 5.2.3。
- 按照 How To Build a Ruby on Rails Application 的 Step 1 安装 SQLite。 本教程使用 SQLite 3 3.22.0。
- 按照 How To Install and Secure Redis on Ubuntu 18.04 的 Steps 1-3 安装 Redis。 本教程使用 Redis 4.0.9。
第 1 步 — 克隆项目并安装依赖项
我们的第一步是从 DigitalOcean 社区 GitHub 帐户 克隆 rails-bootstrap 存储库。 此存储库包含 如何将引导程序添加到 Ruby on Rails 应用程序 中描述的设置中的代码,其中解释了如何将 Bootstrap 添加到现有的 Rails 5 项目。
将存储库克隆到名为 rails-sidekiq
的目录中:
git clone https://github.com/do-community/rails-bootstrap.git rails-sidekiq
导航到 rails-sidekiq
目录:
cd rails-sidekiq
为了使用代码,您首先需要安装项目的依赖项,这些依赖项列在其 Gemfile 中。 您还需要将 sidekiq gem 添加到项目中以使用 Sidekiq 和 Redis。
使用 nano
或您喜欢的编辑器打开项目的 Gemfile 进行编辑:
nano Gemfile
在主项目依赖项(在开发依赖项之上)的任何位置添加 gem:
~/rails-sidekiq/Gemfile
. . . # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.1.0', require: false gem 'sidekiq', '~>6.0.0' group :development, :test do . . .
添加完 gem 后保存并关闭文件。
使用以下命令安装 gem:
bundle install
您将在输出中看到 redis gem 也作为 sidekiq
的要求安装。
接下来,您将安装 Yarn 依赖项。 因为这个 Rails 5 项目已经修改为使用 webpack 提供资产,所以它的 JavaScript 依赖项现在由 Yarn 管理。 这意味着有必要安装并验证项目的 package.json
文件中列出的依赖项。
运行 yarn install
以安装这些依赖项:
yarn install
接下来,运行数据库迁移:
rails db:migrate
迁移完成后,您可以测试应用程序以确保它按预期工作。 如果您在本地工作,请使用以下命令在本地包的上下文中启动您的服务器:
bundle exec rails s
如果您在开发服务器上工作,您可以使用以下命令启动应用程序:
bundle exec rails s --binding=your_server_ip
导航到 localhost:3000
或 http://your_server_ip:3000
。 您将看到以下登录页面:
要创建新鲨鱼,请单击 Get Shark Info 按钮,这将带您到 sharks/index
路线:
为了验证应用程序是否正常工作,我们可以向其添加一些演示信息。 点击 New Shark。 由于项目的 身份验证设置 ,系统将提示您输入用户名 (sammy) 和密码 (shark)。
在 New Shark 页面,在 Name 字段中输入“Great White”,在 Facts 字段中输入“Scary”:
点击Create Shark按钮创建鲨鱼。 一旦你看到你的鲨鱼已经被创建,你可以用 CTRL+C
杀死服务器。
您现在已经为您的项目安装了必要的依赖项并测试了它的功能。 接下来,您可以对 Rails 应用程序进行一些更改,以使用濒临灭绝的鲨鱼资源。
第 2 步 — 为濒危鲨鱼资源生成控制器
为了使用我们濒临灭绝的鲨鱼资源,我们将向应用程序添加一个新模型和一个控制器,该控制器将控制如何将濒危鲨鱼的信息呈现给用户。 我们的最终目标是让用户能够上传大量有关濒临灭绝的鲨鱼的信息,而不会阻塞我们应用程序的整体功能,并在他们不再需要时删除这些信息。
首先,让我们为濒临灭绝的鲨鱼创建一个 Endangered
模型。 我们将在我们的数据库表中包含鲨鱼名称的字符串字段,以及 国际自然保护联盟 (IUCN) 类别 的另一个字符串字段,用于确定每条鲨鱼都处于危险之中。
最终,我们的模型结构将匹配我们将用于创建批量上传的 CSV 文件中的列。 该文件位于db
目录下,可以通过以下命令查看其内容:
cat db/sharks.csv
该文件包含 73 条濒临灭绝的鲨鱼及其 IUCN 状态的列表——vu 表示易受伤害,en 表示濒危,cr 表示极度濒危。
我们的 Endangered
模型将与这些数据相关联,允许我们从这个 CSV 文件创建新的 Endangered
实例。 使用以下命令创建模型:
rails generate model Endangered name:string iucn:string
接下来,生成一个带有 index
动作的 Endangered
控制器:
rails generate controller endangered index
这将为我们提供构建应用程序功能的起点,尽管我们还需要将自定义方法添加到 Rails 为我们生成的控制器文件中。
现在打开该文件:
nano app/controllers/endangered_controller.rb
Rails 为我们提供了一个可以开始填写的骨架轮廓。
首先,我们需要确定处理数据所需的路径。 感谢 generate controller
命令,我们有一个 index
方法开始。 这将与 index
视图相关联,我们将在该视图中为用户提供上传濒临灭绝的鲨鱼的选项。
但是,我们还需要处理用户可能已经上传了鲨鱼的情况; 在这种情况下,他们不需要上传选项。 我们需要以某种方式评估 Endangered
类的实例有多少已经存在,因为不止一个表明批量上传已经发生。
让我们首先创建一个 set_endangered
private
方法,该方法将从数据库中获取我们的 Endangered
类的每个实例。 将以下代码添加到文件中:
~/rails-sidekiq/app/controllers/endangered_controller.rb
class EndangeredController < ApplicationController before_action :set_endangered, only: [:index, :data] def index end private def set_endangered @endangered = Endangered.all end end
请注意,before_action
过滤器将确保 @endangered
的值仅为 index
和 data
路由设置,这将是我们处理濒危的鲨鱼数据。
接下来,将以下代码添加到 index
方法中,以确定用户访问应用程序这一部分的正确路径:
~/rails-sidekiq/app/controllers/endangered_controller.rb
class EndangeredController < ApplicationController before_action :set_endangered, only: [:index, :data] def index if @endangered.length > 0 redirect_to endangered_data_path else render 'index' end end . . .
如果我们的 Endangered
类的实例超过 0 个,我们会将用户重定向到 data
路由,在那里他们可以查看有关他们创建的鲨鱼的信息。 否则,他们将看到 index
视图。
接下来,在 index
方法下方,添加一个 data
方法,它将与 data
视图相关联:
~/rails-sidekiq/app/controllers/endangered_controller.rb
. . . def index if @endangered.length > 0 redirect_to endangered_data_path else render 'index' end end def data end . . .
接下来,我们将添加一个方法来处理数据上传本身。 我们将调用此方法 upload
,它会调用 Sidekiq 工作程序类和方法来执行从 CSV 文件上传的数据。 我们将在下一步中为这个工作类创建定义 AddEndangeredWorker
。
现在,将以下代码添加到文件中以调用 Sidekiq 工作人员执行上传:
~/rails-sidekiq/app/controllers/endangered_controller.rb
. . . def data end def upload csv_file = File.join Rails.root, 'db', 'sharks.csv' AddEndangeredWorker.perform_async(csv_file) redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!' end . . .
通过调用 AddEndangeredWorker
类的 perform_async
方法,使用 CSV 文件作为参数,此代码确保将鲨鱼数据和上传作业传递给 Redis。 我们将设置的 Sidekiq 工作人员监控作业队列,并在新作业出现时做出响应。
调用 perform_async
后,我们的 upload
方法会重定向到 data
路径,用户将可以看到上传的鲨鱼。
接下来,我们将添加一个 destroy
方法来销毁数据。 在 upload
方法下面添加以下代码:
~/rails-sidekiq/app/controllers/endangered_controller.rb
. . . def upload csv_file = File.join Rails.root, 'db', 'sharks.csv' AddEndangeredWorker.perform_async(csv_file) redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!' end def destroy RemoveEndangeredWorker.perform_async redirect_to root_path end . . .
与我们的 upload
方法一样,我们的 destroy
方法包括对 RemoveEndangeredWorker
类的 perform_async
调用——我们将创建的另一个 Sidekiq 工作器。 调用此方法后,它将用户重定向到根应用程序路径。
完成的文件将如下所示:
~/rails-sidekiq/app/controllers/endangered_controller.rb
class EndangeredController < ApplicationController before_action :set_endangered, only: [:index, :data] def index if @endangered.length > 0 redirect_to endangered_data_path else render 'index' end end def data end def upload csv_file = File.join Rails.root, 'db', 'sharks.csv' AddEndangeredWorker.perform_async(csv_file) redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!' end def destroy RemoveEndangeredWorker.perform_async redirect_to root_path end private def set_endangered @endangered = Endangered.all end end
完成编辑后保存并关闭文件。
作为巩固应用程序路由的最后一步,我们将修改 config/routes.rb
中的代码,我们的路由声明所在的文件。
现在打开该文件:
nano config/routes.rb
该文件当前如下所示:
~/rails-sidekiq/config/routes.rb
Rails.application.routes.draw do get 'endangered/index' get 'home/index' resources :sharks do resources :posts end root 'home#index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end
我们需要更新文件以包含我们在控制器中定义的路由:data
、upload
和 destroy
。 我们的 data
路由将匹配 GET 请求以检索鲨鱼数据,而我们的 upload
和 destroy
路由将映射到上传和销毁该数据的 POST 请求。
将以下代码添加到文件中以定义这些路由:
~/rails-sidekiq/config/routes.rb
Rails.application.routes.draw do get 'endangered/index' get 'endangered/data', to: 'endangered#data' post 'endangered/upload', to: 'endangered#upload' post 'endangered/destroy', to: 'endangered#destroy' get 'home/index' resources :sharks do resources :posts end root 'home#index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end
完成编辑后保存并关闭文件。
有了 Endangered
模型和控制器,您现在可以继续定义 Sidekiq 工作程序类。
第三步——定义 Sidekiq Worker
我们在控制器中的 Sidekiq 工作人员上调用了 perform_async
方法,但我们仍然需要自己创建工作人员。
首先,为工人创建一个 workers
目录:
mkdir app/workers
为 AddEndangeredWorker
工作者打开一个文件:
nano app/workers/add_endangered_worker.rb
在这个文件中,我们将添加允许我们使用 CSV 文件中的数据的代码。 首先,将代码添加到将创建类的文件中,包括 Ruby CSV 库,并确保该类作为 Sidekiq Worker 运行:
~/rails-sidekiq/app/workers/add_endangered_worker.rb
class AddEndangeredWorker require 'csv' include Sidekiq::Worker sidekiq_options retry: false end
我们还包括 retry: false
选项,以确保 Sidekiq 在失败的情况下不会重试上传。
接下来,为 perform
函数添加代码:
~/rails-sidekiq/app/workers/add_endangered_worker.rb
class AddEndangeredWorker require 'csv' include Sidekiq::Worker sidekiq_options retry: false def perform(csv_file) CSV.foreach(csv_file, headers: true) do |shark| Endangered.create(name: shark[0], iucn: shark[1]) end end end
perform
方法从控制器中定义的 perform_async
方法接收参数,因此对齐参数值很重要。 在这里,我们传入 csv_file
,这是我们在控制器中定义的变量,我们使用 CSV 库中的 foreach
方法来读取文件中的值。 为此循环设置 headers: true
可确保文件的第一行被视为一行标题。
然后该块将文件中的值读取到我们为 Endangered
模型设置的列中:name
和 iucn
。 运行此循环将为 CSV 文件中的每个条目创建 Endangered
实例。
完成编辑后,保存并关闭文件。
接下来,我们将创建一个工作人员来处理删除这些数据。 打开 RemoveEndangeredWorker
类的文件:
nano app/workers/remove_endangered_worker.rb
添加代码以定义类,并确保它使用 CSV 库并作为 Sidekiq Worker 运行:
~/rails-sidekiq/app/workers/remove_endangered_worker.rb
class RemoveEndangeredWorker include Sidekiq::Worker sidekiq_options retry: false end
接下来,添加一个 perform
方法来处理濒临灭绝的鲨鱼数据的销毁:
~/rails-sidekiq/app/workers/remove_endangered_worker.rb
class RemoveEndangeredWorker include Sidekiq::Worker sidekiq_options retry: false def perform Endangered.destroy_all end end
perform
方法在 Endangered
类上调用 destroy_all
,这将从数据库中删除该类的所有实例。
完成编辑后保存并关闭文件。
工作人员就位后,您可以继续为 endangered
视图创建布局,并为 index
和 data
视图创建模板,以便用户上传和查看濒临灭绝的鲨鱼。
第 4 步 - 添加布局和视图模板
为了让用户享受他们濒临灭绝的鲨鱼信息,我们需要解决两件事:在我们的 endangered
控制器中定义的视图布局,以及 index
和 data
视图。
目前,我们的应用程序使用位于 app/views/layouts/application.html.erb
的应用程序范围的布局、导航部分和 sharks
视图的布局。 应用程序布局检查内容块,这允许我们根据用户正在使用的应用程序的哪个部分加载不同的布局:对于 home
index
页面,他们将看到一个布局,对于与个别鲨鱼有关的任何观点,他们将看到另一个观点。
我们可以为我们的 endangered
视图重新使用 sharks
布局,因为这种格式也适用于批量呈现鲨鱼数据。
复制 sharks
布局文件以创建 endangered
布局:
cp app/views/layouts/sharks.html.erb app/views/layouts/endangered.html.erb
接下来,我们将为我们的 index
和 data
视图创建视图模板。
先打开index
模板:
nano app/views/endangered/index.html.erb
删除样板代码并添加以下代码,这将为用户提供有关濒危类别的一些一般信息,并为他们提供上传濒危鲨鱼信息的选项:
~/rails-sidekiq/app/views/endangered/index.html.erb
<p id="notice"><%= notice %></p> <h1>Endangered Sharks</h1> <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p> <br> <%= form_tag endangered_upload_path do %> <%= submit_tag "Import Endangered Sharks" %> <% end %> <br> <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
form_tag
通过将发布操作指向 endangered_upload_path
(我们为上传定义的路线)使数据上传成为可能。 使用 submit_tag
创建的提交按钮会提示用户选择 "Import Endangered Sharks"
。
除了此代码之外,我们还包含了一些有关 ICUN 代码的一般信息,以便用户可以解释他们将看到的数据。
完成编辑后保存并关闭文件。
接下来,为 data
视图打开一个文件:
nano app/views/endangered/data.html.erb
添加以下代码,这将添加一个包含濒危鲨鱼数据的表:
~/rails-sidekiq/app/views/endangered/data.html.erb
<p id="notice"><%= notice %></p> <h1>Endangered Sharks</h1> <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p> <div class="table-responsive"> <table class="table table-striped table-dark"> <thead> <tr> <th>Name</th> <th>IUCN Status</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @endangered.each do |shark| %> <tr> <td><%= shark.name %></td> <td><%= shark.iucn %></td> </tr> <% end %> </tbody> </table> </div> <br> <%= form_tag endangered_destroy_path do %> <%= submit_tag "Delete Endangered Sharks" %> <% end %> <br> <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
该代码再次包含 ICUN 状态代码,以及用于输出数据的 Bootstrap 表。 通过循环我们的 @endangered
变量,我们将每条鲨鱼的名称和 ICUN 状态输出到表中。
在表格下方,我们有另一组 form_tags
和 submit_tags
,它们通过为用户提供 "Delete Endangered Sharks"
选项来发布到 destroy
路径。
完成编辑后保存并关闭文件。
我们将对视图进行的最后修改将在与我们的 home
控制器关联的 index
视图中。 您可能还记得这个视图被设置为 config/routes.rb
中应用程序的根。
打开此文件进行编辑:
nano app/views/home/index.html.erb
在行中找到声明 Sharks are ancient
的列:
~/rails-sidekiq/app/views/home/index.html.erb
. . . <div class="col-lg-6"> <h3>Sharks are ancient</h3> <p>There is evidence to suggest that sharks lived up to 400 million years ago. </p> </div> </div> </div>
将以下代码添加到文件中:
~/rails-sidekiq/app/views/home/index.html.erb
. . . <div class="col-lg-6"> <h3>Sharks are ancient and SOME are in danger</h3> <p>There is evidence to suggest that sharks lived up to 400 million years ago. Without our help, some could disappear soon.</p> <p><%= button_to 'Which Sharks Are in Danger?', endangered_index_path, :method => :get, :class => "btn btn-primary btn-sm"%> </p> </div> </div> </div>
我们已经包含了一个行动呼吁,让用户了解更多关于濒临灭绝的鲨鱼,首先分享一个强烈的信息,然后添加一个 button_to
助手,向我们的 endangered
[X195X 提交一个 GET 请求] 路由,允许用户访问应用程序的该部分。 从那里,他们将能够上传和查看濒临灭绝的鲨鱼信息。
完成编辑后保存并关闭文件。
准备好代码后,您就可以启动应用程序并上传一些鲨鱼了!
第 5 步 — 启动 Sidekiq 并测试应用程序
在我们启动应用程序之前,我们需要在我们的数据库上运行迁移并启动 Sidekiq 以启用我们的工作人员。 Redis 应该已经在服务器上运行,但我们可以检查以确保。 有了所有这些东西,我们就可以测试应用程序了。
首先,检查 Redis 是否正在运行:
systemctl status redis
您应该看到如下输出:
Output● redis-server.service - Advanced key-value store Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2019-11-12 20:37:13 UTC; 1 weeks 0 days ago
接下来,运行数据库迁移:
rails db:migrate
您现在可以使用 bundle exec sidekiq
命令在当前项目包的上下文中启动 Sidekiq:
bundle exec sidekiq
您将看到如下输出,表明 Sidekiq 已准备好处理作业:
Output m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$b/md$$$P^' .d$$$$$$/$$$P' $$^' `"/$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Running in ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux] 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: See LICENSE and the LGPL-3.0 for licensing details. 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Booting Sidekiq 6.0.3 with redis options {:id=>"Sidekiq-server-PID-17621", :url=>nil} 2019-11-19T21:43:00.543Z pid=17621 tid=gpiqiesdl INFO: Starting processing, hit Ctrl-C to stop
打开第二个终端窗口,导航到 rails-sidekiq
目录,然后启动您的应用程序服务器。
如果您在本地运行应用程序,请使用以下命令:
bundle exec rails s
如果您正在使用开发服务器,请运行以下命令:
bundle exec rails s --binding=your_server_ip
在浏览器中导航到 localhost:3000
或 http://your_server_ip:3000
。 您将看到以下登录页面:
点击哪些鲨鱼处于危险之中?按钮。 由于您尚未上传任何濒临灭绝的鲨鱼,这将带您进入 endangered
index
视图:
点击导入濒危鲨鱼导入鲨鱼。 您将看到一条状态消息,告诉您鲨鱼已被导入:
您还将看到导入的开始。 刷新页面以查看整个表格:
多亏了 Sidekiq,我们大批量上传濒临灭绝的鲨鱼已经成功,没有锁定浏览器或干扰其他应用程序功能。
点击页面底部的Home按钮,返回应用主页面:
从这里,再次单击哪些鲨鱼处于危险之中?。 现在这将带您直接进入 data
视图,因为您已经上传了鲨鱼。
要测试删除功能,请单击表格下方的 Delete Endangered Sharks 按钮。 您应该再次被重定向到主页应用程序页面。 点击 Which Sharks Are in Danger? 最后一次将带您回到 index
视图,您将可以选择再次上传鲨鱼:
您的应用程序现在正在使用 Sidekiq 工作人员运行,这些工作人员已准备好处理作业并确保用户在使用您的应用程序时拥有良好的体验。
结论
您现在有一个启用了 Sidekiq 的可用 Rails 应用程序,这将允许您将昂贵的操作卸载到由 Sidekiq 管理并由 Redis 支持的作业队列。 这将允许您在开发过程中提高网站的速度和功能。
如果您想了解更多关于 Sidekiq 的信息,docs 是一个很好的起点。
要了解有关 Redis 的更多信息,请查看我们的 Redis 资源库。 您还可以通过查看 产品文档 了解有关在 DigitalOcean 上运行托管 Redis 集群的更多信息。