<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>luolinae86 (罗林)</title>
    <link>https://ruby-china.org/luolinae86</link>
    <description>因为热爱，所以不知疲倦</description>
    <language>en-us</language>
    <item>
      <title>Rails 多节点日志合并查询</title>
      <description>&lt;h4 id="场景"&gt;场景&lt;/h4&gt;
&lt;p&gt;业务基于 &lt;code&gt;ruby on rails&lt;/code&gt; 用 &lt;code&gt;sidekiq&lt;/code&gt; 做异步队列，运行在 N 台服务器，N &amp;gt; 1，没有专门的日志服务器。&lt;/p&gt;

&lt;p&gt;业务定位问题，需要在 N 台机器的日志中搜索关键字，这样效率低。&lt;/p&gt;
&lt;h4 id="解决方案"&gt;解决方案&lt;/h4&gt;
&lt;p&gt;将 N 台机器日志，合并到一台目标机器，在目标机器上面查看最终日志搜索结果，这样效率高。&lt;/p&gt;

&lt;p&gt;假定有 3 台机器：A，B，C。&lt;/p&gt;

&lt;p&gt;目标是在 A 上执行脚本，一键将 B，C 机器日志拉取到 A 机器。&lt;/p&gt;
&lt;h4 id="方法"&gt;方法&lt;/h4&gt;&lt;h5 id="1. 将服务器A 公钥添加到B，C机器信任列表"&gt;1. 将服务器 A 公钥添加到 B，C 机器信任列表&lt;/h5&gt;
&lt;p&gt;在机器 A 上执行&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 将下面的值拷贝&lt;/span&gt;
more ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在机器 B,C 上执行&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 将拷贝的值追加到 authorized_keys&lt;/span&gt;
vim ~/.ssh/authorized_keys 
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="2. 添加远程执行的脚本"&gt;2. 添加远程执行的脚本&lt;/h5&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;server &lt;span class="k"&gt;in &lt;/span&gt;B-INNER-IP  C-INNER-IP&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c"&gt;# 注 B-INNER-IP 和 C-INNER-IP 是 B/C 服务器的内网IP地址&lt;/span&gt;
  &lt;span class="c"&gt;# deployer 是 B/C服务器的用户名 $1和$2 是执行脚本传入的第一，第二个参数， (date +%F) 是当天时间，比如： '2022-11-27'&lt;/span&gt;
  &lt;span class="c"&gt;# 以下语句： 远程ssh到B或C的指定目录， 在文件 $1中按关键字$2搜索今天的日志，追加到机器 A 的 /tmp/$1 目录&lt;/span&gt;
  ssh &lt;span class="nt"&gt;-t&lt;/span&gt; deployer@&lt;span class="nv"&gt;$server&lt;/span&gt; &lt;span class="s1"&gt;'cd /home/deployer/wai_mai/shared/log; more '&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s1"&gt;' |grep "$(date +%F)" | grep '&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"##### 节点 &lt;/span&gt;&lt;span class="nv"&gt;$server&lt;/span&gt;&lt;span class="s2"&gt; 传输完成#####"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注&lt;/strong&gt; 在 B，C 机器按关键字搜索后，再回传到机器 A，而不是将 B，C 机器整个日志传到 A，再在 A 上面进行搜索，这样可以大大降低网络传输。&lt;/p&gt;

&lt;p&gt;将脚本命名为： &lt;code&gt;merge_log.sh&lt;/code&gt;，添加可执行权限&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;700 merge_log.sh
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="3. 执行脚本"&gt;3. 执行脚本&lt;/h5&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 从机器 B，C上，找到今天在日志 `unicorn.stdout.log` 出现关键字 `588e6f3837b74dfdb827ba4d5e614645` 的所有日志，并存储到 A 机器的 /tmp/unicorn.stdout.log 文件中&lt;/span&gt;
./merge_log.sh  unicorn.stdout.log 588e6f3837b74dfdb827ba4d5e614645

&lt;span class="c"&gt;# 从机器 B，C上，找到今天在日志 `sidekiq.log` 出现关键字 `1100303332560786082` 的所有日志，并存储到 A 机器的 /tmp/sidekiq.log 文件中&lt;/span&gt;
./merge_log.sh sidekiq.log 1100303332560786082
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="备注"&gt;备注&lt;/h4&gt;
&lt;p&gt;目前的方式，对于机器都在一个内网中，整体执行效率较高。&lt;/p&gt;

&lt;p&gt;如果大家有更加优雅的日志合并和查询的方案，也请留言。&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Sun, 27 Nov 2022 17:17:43 +0800</pubDate>
      <link>https://ruby-china.org/topics/42766</link>
      <guid>https://ruby-china.org/topics/42766</guid>
    </item>
    <item>
      <title>优雅地更新数据库索引</title>
      <description>&lt;h3 id="业务背景"&gt;业务背景&lt;/h3&gt;
&lt;p&gt;业务中有一个表按列创建了普通单列索引，但是没有唯一性约束，现在想要为这个字段添加唯一性索引。&lt;/p&gt;

&lt;p&gt;比如我们需要对通知记录表 &lt;code&gt;notifications&lt;/code&gt; 的 &lt;code&gt;order_id&lt;/code&gt; 字段添加唯一约束，但是这个表已经有了 &lt;code&gt;order_id&lt;/code&gt; 的普通索引。&lt;/p&gt;
&lt;h4 id="不优雅的做法"&gt;不优雅的做法&lt;/h4&gt;
&lt;p&gt;直接添加唯一索引，当数据库里面已经存在&lt;code&gt;order_id&lt;/code&gt;重复记录的时候会报错。&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;Duplicate&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="s1"&gt;'index_notifications_on_order_id'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果直接删除索引，再新建索引，在索引新建完成前，业务会受到影响，涉及到按&lt;code&gt;order_id&lt;/code&gt; 查询记录的会导致全表扫描，影响数据库性能&lt;/p&gt;
&lt;h4 id="优雅的处理方式"&gt;优雅的处理方式&lt;/h4&gt;
&lt;p&gt;以 &lt;code&gt;notifications&lt;/code&gt; 表为例&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;删除表中&lt;code&gt;order_id&lt;/code&gt;字段重复的记录&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_duplicated_records&lt;/span&gt;
  &lt;span class="c1"&gt;# 查找存在重复的记录&lt;/span&gt;
  &lt;span class="n"&gt;dup_order_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:order_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;having&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'COUNT(*) &amp;gt; 1'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pluck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:order_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;dup_order_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;order_ids&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;not_remove_order_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;order_id: &lt;/span&gt;&lt;span class="n"&gt;order_ids&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:order_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;having&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'COUNT(*) &amp;gt; 1'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pluck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MIN(id)'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;order_id: &lt;/span&gt;&lt;span class="n"&gt;order_ids&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;not_remove_order_ids&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;destroy_all&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;将原索引重命名&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;rename_index&lt;/span&gt; &lt;span class="ss"&gt;:notifications&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:index_notifications_on_order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:non_uniq_index_notifications_on_order_id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;添加唯一索引&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;add_index&lt;/span&gt; &lt;span class="ss"&gt;:notifications&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unique: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;删除原索引&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;remove_index&lt;/span&gt; &lt;span class="ss"&gt;:notifications&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name: :non_uniq_index_notifications_on_order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;column: :order_id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="注意事项"&gt;注意事项&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;涉及到索引的创建，当表数据量比较大时，一定要避开业务高峰期，切记！！！&lt;/li&gt;
&lt;li&gt;删除重复记录之前，如果数据对业务有用的，可以先将数据进行拷贝&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 28 Sep 2022 11:56:29 +0800</pubDate>
      <link>https://ruby-china.org/topics/42672</link>
      <guid>https://ruby-china.org/topics/42672</guid>
    </item>
    <item>
      <title>【Sensitive】基于 DFA 算法的 Ruby 敏感词过滤 Gem</title>
      <description>&lt;p&gt;分享一个最近写的 基于 DFA 算法的 Ruby 敏感词过滤 Gem&lt;/p&gt;
&lt;h4 id="项目地址"&gt;项目地址&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://github.com/luolinae86/sensitive" rel="nofollow" target="_blank" title=""&gt;Sensitive 代码&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="背景"&gt;背景&lt;/h4&gt;
&lt;p&gt;项目开发中，会涉及到敏感词的过滤，大家多是自己在实现自己的算法，读了 sanvi 的 &lt;a href="https://ruby-china.org/topics/39859" title=""&gt;敏感词过滤实现&lt;/a&gt; 文章，了解到了 DFA 算法，看了 huobazi 在 4 楼的回复，收获颇大，但最终让我写这个 Gem 的原因是  Rei 在 3 楼的一句留言 &lt;code&gt;完善成 Gem 有前途（词库自己加）&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;经过几天的努力，基于 DFA 算法的 Ruby 敏感词过滤 Gem 它来了&lt;/p&gt;
&lt;h2 id="使用方法"&gt;使用方法&lt;/h2&gt;&lt;h4 id="选择是否加载 Gem 自带敏感词库"&gt;选择是否加载 &lt;code&gt;Gem&lt;/code&gt; 自带敏感词库&lt;/h4&gt;
&lt;p&gt;本着主厨思想，Gem 内置了 1 万多条&lt;a href="https://github.com/observerss/textfilter" rel="nofollow" target="_blank" title=""&gt;敏感词库&lt;/a&gt;。
我花了一整天时间，将词库的内容和格式进行了整理，整理完之后，视力下降了不少，自己慢慢也变成了合格的鉴黄师。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Gem&lt;/code&gt; 自带敏感词，涉及&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;广告&lt;/li&gt;
&lt;li&gt;政治&lt;/li&gt;
&lt;li&gt;色情&lt;/li&gt;
&lt;li&gt;其它&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;你可以根据自己选择是否加载，加载方法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="加载自己的敏感词文件"&gt;加载自己的敏感词文件&lt;/h4&gt;
&lt;p&gt;你也可以加载自己的一个或多个敏感词文件，文件格式支持 &lt;code&gt;txt&lt;/code&gt;，不同的敏感词条独立一行&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="动态添加单个敏感词"&gt;动态添加单个敏感词&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_word&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'赌博'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="清空敏感词"&gt;清空敏感词&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="敏感词过滤"&gt;敏感词过滤&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# filter 方法传入需要检测的敏感字符串,如果字符串中有敏感词，则返回，如果没有，则返回空&lt;/span&gt;
&lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'不要赌博'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; '赌博'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;001&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'sensitive'&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;01&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;01&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_word&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'敏感词'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"敏"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"感"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"词"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;020&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"敏"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:is_end&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:value&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"感"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:is_end&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:value&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"词"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:is_end&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:value&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{}}}}}}}&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;021&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'检测敏感词的算法'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;敏感词&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;022&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'色情信息'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;023&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_default&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;024&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'色情信息'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;色情信息&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;025&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty!&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;026&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Sensitive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="使用建议"&gt;使用建议&lt;/h3&gt;
&lt;p&gt;Gem 自带敏感词库里面的内容，如不能满足业务需要的，请自己添加和丰富词库，词库的内容一定要精减和准确。&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 24 Jun 2020 11:39:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/39997</link>
      <guid>https://ruby-china.org/topics/39997</guid>
    </item>
    <item>
      <title>[成都] 四川必顾养老信息咨询有限公司  诚招 Ruby on Rails 工程师 1 名  月薪 12K-20K</title>
      <description>&lt;h3 id="我们是谁"&gt;我们是谁&lt;/h3&gt;
&lt;p&gt;必顾养老是四川省最大的智慧养老院平台供应商。&lt;/p&gt;

&lt;p&gt;随着人口老龄化加剧，养老产业迅速成为全球性的朝阳行业。&lt;/p&gt;

&lt;p&gt;我们致力于用信息技术推动产业发展，让养老产业基业长青！&lt;/p&gt;
&lt;h3 id="Ruby On Rails 开发工程师 1名 （12k-20k）"&gt;Ruby On Rails 开发工程师 1 名（12k-20k）&lt;/h3&gt;&lt;h4 id="岗位职责"&gt;岗位职责&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;使用 ruby on rails 开发 web 应用及移动端后台服务&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="岗位要求"&gt;岗位要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;2 年以上的 Rails 项目经验&lt;/li&gt;
&lt;li&gt;熟悉 Linux 操作系统&lt;/li&gt;
&lt;li&gt;掌握 Mysql、Redis、Nginx&lt;/li&gt;
&lt;li&gt;能熟悉使用 HTML/CSS/JavaScript&lt;/li&gt;
&lt;li&gt;能熟练运用 Git&lt;/li&gt;
&lt;li&gt;熟悉阿里云的生态环境，包含云服务器，云数据库，云存储等&lt;/li&gt;
&lt;li&gt;优秀的程序设计、编写能力。能把良好的设计理念，思想落实到项目实践中&lt;/li&gt;
&lt;li&gt;学习能力强，能独立解决问题，工作努力，责任心强&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;福利齐全，周末双休，年假 /调薪 /年终奖 一个都不能少~~~~&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="简历投递方式"&gt;简历投递方式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;地点：成都 - 高新区 - 益州大道 1999 号 15 栋阿里中心&lt;/li&gt;
&lt;li&gt;联系方式：13096397900&lt;/li&gt;
&lt;li&gt;邮箱：wayne.duan@ktbhealth.com &lt;/li&gt;
&lt;/ul&gt;</description>
      <author>luolinae86</author>
      <pubDate>Mon, 10 Jun 2019 11:00:37 +0800</pubDate>
      <link>https://ruby-china.org/topics/38616</link>
      <guid>https://ruby-china.org/topics/38616</guid>
    </item>
    <item>
      <title>解决 mina unicorn restart 不生效的问题</title>
      <description>&lt;h2 id="问题描述"&gt;问题描述&lt;/h2&gt;
&lt;p&gt;目前的项目，基于 nginx + unicorn + mina 进行部署&lt;/p&gt;

&lt;p&gt;其中，mina 无缝重启 unicorn 是用的 mina-unicorn 这个 gem&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/scarfacedeb/mina-unicorn" rel="nofollow" target="_blank"&gt;https://github.com/scarfacedeb/mina-unicorn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;具体的部署方式，可以参考之前写过的一篇部署帖子&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://ruby-china.org/topics/26661" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/26661&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;但有时，发现成功执行了 mina deploy，代码更新到了远程服务器，unicorn 进程重启过，unicorn 的 pid 也改变了，但新增加的功能却没有生效。&lt;/p&gt;

&lt;p&gt;查阅了论坛，也看到之前已经有用户遇到了相同的问题，因此，得想办法解决。&lt;/p&gt;
&lt;h2 id="问题解决"&gt;问题解决&lt;/h2&gt;
&lt;p&gt;mina-unicorn 重启 unicorn 的命令 unicorn:restart 源码在此&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 作者也注释过了，借鉴的 capistrano-unicorn &lt;/span&gt;
&lt;span class="c1"&gt;# Ported from: https://github.com/sosedoff/capistrano-unicorn/blob/master/lib/capistrano-unicorn/utility.rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/scarfacedeb/mina-unicorn/blob/master/lib/mina/unicorn/utility.rb" rel="nofollow" target="_blank"&gt;https://github.com/scarfacedeb/mina-unicorn/blob/master/lib/mina/unicorn/utility.rb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;查看了源码，没有发现太多的端倪，但思路是先停 unicorn，再启动 unicorn
因此，自己重写了 config/deployer.rb 中的 unicorn:restart 部分&lt;/p&gt;

&lt;p&gt;增加了 代码如下&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:unicorn&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/unicorn.pid"&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Start Unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:start&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="s1"&gt;'echo "-----&amp;gt; Start Unicorn"'&lt;/span&gt;
    &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%{
      cd &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt; &amp;amp;&amp;amp; bundle exec unicorn_rails -c config/unicorn.rb -E production -D
    }&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Stop Unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:stop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="s1"&gt;'echo "-----&amp;gt; Stop Unicorn"'&lt;/span&gt;
    &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%{
      kill -QUIT `cat "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;unicorn_pid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;"` &amp;amp;&amp;amp; rm -rf "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;unicorn_pid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;" &amp;amp;&amp;amp; echo "Stop Ok" &amp;amp;&amp;amp; exit 0
      echo &amp;gt;&amp;amp;2 "Not running"
    }&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Restart unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:restart&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="s1"&gt;'unicorn:stop'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="s1"&gt;'unicorn:start'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="config/deployer.rb 文件更新"&gt;config/deployer.rb 文件更新&lt;/h2&gt;
&lt;p&gt;使用上面的代码之后，就可以不用再引用 mina/unicorn这个文件，下面是整个config/deployer.rb配置文件，供参考&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/bundler'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/rails'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/git'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/rvm'&lt;/span&gt;
&lt;span class="c1"&gt;#require 'mina/unicorn' 不再需要了&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"mina_sidekiq/tasks"&lt;/span&gt;

&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:bundle_gemfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Gemfile"&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:deploy_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/data/project/your_project'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:bundle_gemfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Gemfile"&lt;/span&gt;

&lt;span class="c1"&gt;#设置git地址及分支&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'your_git.git'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'develop'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:shared_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'config/database.yml'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'config/local_env.yml'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;#设置sidekiq unicorn 的进程保存地址&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:sidekiq_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/sidekiq.pid"&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/unicorn.pid"&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rvm:use[ruby-ruby-2.3.0]'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:setup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# unicorn and sidekiq needs a place to store its pid file&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/tmp/sockets/"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/tmp/pids/"]&lt;/span&gt;

  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/log"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config"]&lt;/span&gt;

  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/local_env.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/database.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue&lt;/span&gt;  &lt;span class="sx"&gt;%[echo "-----&amp;gt; Be sure to edit '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/database.yml','local_env.yml'."]&lt;/span&gt;

  &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="sx"&gt;%[
    repo_host=`echo $repo | sed -e 's/.*@//g' -e 's/:.*//g'` &amp;amp;&amp;amp;
    repo_port=`echo $repo | grep -o ':[0-9]*' | sed -e 's/://g'` &amp;amp;&amp;amp;
    if [ -z "${repo_port}" ]; then repo_port=22; fi ]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;development_ip&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_name&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:rvm_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/home/raymond/.rvm/bin/rvm'&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:rails_env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'development'&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'development'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:production&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;production_ip&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_name&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:rvm_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/usr/local/rvm/bin/rvm'&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:rails_env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Deploys the current version to the server."&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:deploy&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="ss"&gt;:before_hook&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Put things to run locally before ssh&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;deploy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# sidekiq stop accepting new workers&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'sidekiq:quiet'&lt;/span&gt;

    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'git:clone'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'deploy:link_shared_paths'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'bundle:install'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rails:db_migrate'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rails:assets_precompile'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'deploy:cleanup'&lt;/span&gt;

    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="ss"&gt;:launch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'sidekiq:restart'&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'unicorn:restart'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# 新增加的 unicorn重启相关命令&lt;/span&gt;
&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:unicorn&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/unicorn.pid"&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Start Unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:start&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="s1"&gt;'echo "-----&amp;gt; Start Unicorn"'&lt;/span&gt;
    &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%{
      cd &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt; &amp;amp;&amp;amp; bundle exec unicorn_rails -c config/unicorn.rb -E production -D
    }&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Stop Unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:stop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="s1"&gt;'echo "-----&amp;gt; Stop Unicorn"'&lt;/span&gt;
    &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%{
      kill -QUIT `cat "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;unicorn_pid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;"` &amp;amp;&amp;amp; rm -rf "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;unicorn_pid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;" &amp;amp;&amp;amp; echo "Stop Ok" &amp;amp;&amp;amp; exit 0
      echo &amp;gt;&amp;amp;2 "Not running"
    }&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Restart unicorn"&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:restart&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="s1"&gt;'unicorn:stop'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="s1"&gt;'unicorn:start'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;目前，使用以上配置，使用 mina 远程部署，之前部署中所遇到的 unicorn 重启后，业务不生效的问题，得到了解决。&lt;/p&gt;

&lt;p&gt;希望该帖子能够帮助到，之前遇到相同问题，但还没有解决的用户。&lt;/p&gt;

&lt;p&gt;如果之前使用 mina 部署的用户，没有遇到和我类似的问题，个人建议大家继续使用 mina-unicorn 这个 gem，毕竟使用起来也很方便。&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Tue, 27 Nov 2018 12:14:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/37821</link>
      <guid>https://ruby-china.org/topics/37821</guid>
    </item>
    <item>
      <title>Rails 集成 RabbitMQ 消息队列实践</title>
      <description>&lt;p&gt;什么是消息队列，什么是 RabbitMQ，重点推荐以下书籍，能够让你真正理解消息队列的发展历史，以及 RabbitMQ 的方方面面。&lt;/p&gt;
&lt;h2 id="参考文献"&gt;参考文献&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;《RabbitMQ 实战》高效部署分布式消息队列     美 Alvaro Videla  / Jason J.W William 著  汪佳南 译&lt;br&gt;
      购买链接： &lt;a href="https://item.jd.com/11790530.html" rel="nofollow" target="_blank"&gt;https://item.jd.com/11790530.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;下面，我主要介绍一下 RabbitMQ server 以及 Client 端的安装配置，以及在 Ruby On Rails 中利用 Bunny 发布消息，用 Sneakers 消费消息的详细介绍及使用说明，希望对正在使用 RabbitMQ 以及即将使用 RabbitMQ 的朋友一些参考。&lt;/p&gt;
&lt;h2 id="RabbitMQ"&gt;RabbitMQ&lt;/h2&gt;&lt;h3 id="安装"&gt;安装&lt;/h3&gt;
&lt;p&gt;Ubuntu 环境下的安装方法&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#更新包&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="c"&gt;#安装&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;rabbitmq-server
&lt;span class="c"&gt;#启动rabbit-server 服务默认启动在5672端口&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;rabbitmq-server start
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="启用Rabbitmq_management插件"&gt;启用 Rabbitmq_management 插件&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#需要从web上面管理控制RabbitMQ&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;rabbitmq-plugins &lt;span class="nb"&gt;enable &lt;/span&gt;rabbitmq_management
&lt;span class="c"&gt;#重启服务以让其生效，控制台默认运行在15672端口&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;rabbitmqctl stop
&lt;span class="nb"&gt;sudo &lt;/span&gt;rabbitmq-server &lt;span class="nt"&gt;-detached&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="创建用户"&gt;创建用户&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#创建用户&lt;/span&gt;
rabbitmqctl  add_user user_name password
&lt;span class="c"&gt;#给权限&lt;/span&gt;
rabbitmqctl set_user_tags user_name administrator
rabbitmqctl set_permissions &lt;span class="nt"&gt;-p&lt;/span&gt; / user_name &lt;span class="s2"&gt;".*"&lt;/span&gt; &lt;span class="s2"&gt;".*"&lt;/span&gt; &lt;span class="s2"&gt;".*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问 &lt;a href="http://rabbitmq-server-ip:15672" rel="nofollow" target="_blank"&gt;http://rabbitmq-server-ip:15672&lt;/a&gt; 以 &lt;code&gt;user_name&lt;/code&gt;和&lt;code&gt;password&lt;/code&gt;登陆 web 控制台&lt;/p&gt;

&lt;p&gt;注：访问 &lt;strong&gt;15672&lt;/strong&gt; 或者 &lt;strong&gt;5672&lt;/strong&gt; 端口以前，请确保本地防火墙，或者阿里云的安全组打开了端口的访问限制&lt;/p&gt;
&lt;h2 id="生产者 (使用 Bunny)"&gt;生产者 (使用 Bunny)&lt;/h2&gt;
&lt;p&gt;Bunny 是一个使用 Ruby 连接和操作 RabbitMQ 的客户端，参考&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/ruby-amqp/bunny" rel="nofollow" target="_blank"&gt;https://github.com/ruby-amqp/bunny&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;其中，Bunny 的标准使用，可以参考 Bunny 官方 Gem 使用手册，按步骤：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;创建一条和 RabbitMQ 消息服务器的真实 TCP 连接&lt;/li&gt;
&lt;li&gt;在 TCP 链接上面创建 AMQP 信道（channel）&lt;/li&gt;
&lt;li&gt;在信道上面申明队列&lt;/li&gt;
&lt;li&gt;队列将消息发布到交换器&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;官方代码示例（&lt;strong&gt;实际生产环境中使用，需要包装代码，后面会有详细说明原因&lt;/strong&gt;）&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"bunny"&lt;/span&gt;

&lt;span class="c1"&gt;# Start a communication session with RabbitMQ&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Bunny&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;

&lt;span class="c1"&gt;# open a channel&lt;/span&gt;
&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_channel&lt;/span&gt;

&lt;span class="c1"&gt;# declare a queue&lt;/span&gt;
&lt;span class="n"&gt;q&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"test1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# publish a message to the default exchange which then gets routed to this queue&lt;/span&gt;
&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello, everybody!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# fetch a message from the queue&lt;/span&gt;
&lt;span class="n"&gt;delivery_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"This is the message: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# close the connection&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="业务代码包装"&gt;业务代码包装&lt;/h3&gt;
&lt;p&gt;新建&lt;code&gt;config/initializers/rabbitmq.rb&lt;/code&gt;文件，代码如下&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RabbitMQ&lt;/span&gt;
  &lt;span class="c1"&gt;# 可以前提前在MQ Web上面创建好exchange和queue，并创建好绑定和路由的关系&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="c1"&gt;#全局创建一个单例@connection，这样一个进程只会和RabbmitMQ服务器建立一条真实的TCP连接&lt;/span&gt;
    &lt;span class="c1"&gt;#这里的ENV['mq_connection']，配置在环境变量里面，例如: amqp://user_name:password@rabbitmq_server_ip&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connection&lt;/span&gt;
      &lt;span class="vi"&gt;@connection&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Bunny&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'mq_connection'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;channel&lt;/span&gt;
      &lt;span class="vi"&gt;@channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_channel&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;# for example： exchange = RabbitMQ.exchange("exchange_name", {durable: true_or_false, queue: :queue_name})&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
      &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;routing_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
      &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;routing_key: &lt;/span&gt;&lt;span class="n"&gt;routing_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面说一下为什么一个应用创建一个 TCP 链接（connection)，多个信道（channel）。&lt;/p&gt;

&lt;p&gt;首先，我们必须先连接到 RabbitMQ，才能消费或者发布消息。应用程序和 Rabbit 代理服务器之间创建一条 TCP 连接。一旦 TCP 连接打开（通过了认证），应用程序就可以创建一条 AMQP 信道。信道是建立在“真实的”TCP 连接内的虚拟连接。不论是发布消息、订阅消息还是接收消息，都是通过信道完成的。&lt;/p&gt;

&lt;p&gt;为什么用信道而不是直接通过 TCP 连接发送 AMQP 命令呢？主要原因是频繁地建立和销毁 TCP，操作系统的开销非常昂贵。比如，当业务高峰的时候，那么每秒都会有大量的 TCP 连接的创建和销毁，这会造成系统 TCP 连接资源的浪费，很快就出遇到系统的性能瓶颈。&lt;/p&gt;

&lt;p&gt;因此，引入了信道 channel 的概念，在一条认证过 TCP 的连接上面每秒可以创建成百上千个信道，而不会影响操作系统，并且，在一条 TCP 连接上面创建多少条信道是没有限制的。&lt;/p&gt;
&lt;h3 id="业务代码调用"&gt;业务代码调用&lt;/h3&gt;
&lt;p&gt;根据上面业务包装的代码，可以简单地实现向 MQ 的消息队列生产消息了&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;exchange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RabbitMQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"exchange_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;durable: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;queue: :queue_name&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;site: :rubychina&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"your_routing_key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="消费者 (使用 Sneakers)"&gt;消费者 (使用 Sneakers)&lt;/h2&gt;
&lt;p&gt;业务通过 Bunny 在 Rails 中简易、快速地生产发布了消息，就需要有消费者来接收和消费消息，Sneakers 是一个处理 RabbitMQ 消息队列的高性能 Ruby 框架&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/jondot/sneakers" rel="nofollow" target="_blank"&gt;https://github.com/jondot/sneakers&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="Rails 集成 Sneakers"&gt;Rails 集成 Sneakers&lt;/h3&gt;
&lt;p&gt;下面介绍怎么在 Rails 里面使用 Sneaker&lt;/p&gt;

&lt;p&gt;1.添加 sneakers gem 包&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'sneakers'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.Rakefile 引用 seakers/tasks&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#Rakefile&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'sneakers/tasks'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.配置 sneakers&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 新建 config/initializers/seakers.rb&lt;/span&gt;
&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;daemonize: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;amqp: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'mq_connection'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;log: &lt;/span&gt;&lt;span class="s2"&gt;"log/sneakers.log"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;pid_path: &lt;/span&gt;&lt;span class="s2"&gt;"tmp/pids/sneakers.pid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;threads: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;workers: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="no"&gt;Sneakers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Sneakers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;INFO&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4.添加 worker&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 新建文件 app/workers/galaxy_worker.rb&lt;/span&gt;
&lt;span class="c1"&gt;# Seaker 作为消费者，消费binding 为 galaxy.queue的队列&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GalaxyWorker&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Sneakers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;
  &lt;span class="c1"&gt;# worker从galaxy.queue队列里面取数据&lt;/span&gt;
  &lt;span class="n"&gt;from_queue&lt;/span&gt; &lt;span class="s2"&gt;"galaxy.queue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;env: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="s2"&gt;"GalaxyWorker::work msg &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# 给队列发送确认信息&lt;/span&gt;
    &lt;span class="n"&gt;ack!&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5.启动 Sneaker 消费队列&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;WORKERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;GalaxyWorker rake sneakers:run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样 sneaker 就以 GalaxyWorker 这个 worker 在后台接收和处理消息&lt;/p&gt;
&lt;h2 id="样例展示"&gt;样例展示&lt;/h2&gt;&lt;h3 id="生产消息"&gt;生产消息&lt;/h3&gt;
&lt;p&gt;启动 Rails 项目，在 console 里面执行&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Loading&lt;/span&gt; &lt;span class="n"&gt;development&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt; &lt;span class="mf"&gt;6.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RabbitMQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"print.exchange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;durable: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="ss"&gt;queue: :print&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Bunny::Exchange:0x00007fb88fb0c6e8&lt;/span&gt;
 &lt;span class="vi"&gt;@arguments&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@auto_delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@bindings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Set: {}&amp;gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="c1"&gt;#&amp;lt;Bunny::Channel:70215330701360 @id=1 @connection=#&amp;lt;Bunny::Session:0x7fb88fae7348 deployer@*.*.*.*:5672, vhost=/, addresses=[*.*.*.*:5672]&amp;gt;&amp;gt; @open=true,&lt;/span&gt;
 &lt;span class="vi"&gt;@durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@internal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"print.exchange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:queue&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;:print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:nowait&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:durable&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="vi"&gt;@type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;:direct&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;pry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;site: :rubychina&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="ss"&gt;routing_key: &lt;/span&gt;&lt;span class="s1"&gt;'print.key'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Bunny::Exchange:0x00007fb88fb0c6e8&lt;/span&gt;
 &lt;span class="vi"&gt;@arguments&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@auto_delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@bindings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Set: {}&amp;gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="c1"&gt;#&amp;lt;Bunny::Channel:70215330701360 @id=1 @connection=#&amp;lt;Bunny::Session:0x7fb88fae7348 deployer@*.*.*.*:5672, vhost=/, addresses=[*.*.*.*:5672]&amp;gt;&amp;gt; @open=true,&lt;/span&gt;
 &lt;span class="vi"&gt;@durable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@internal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"print.exchange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="vi"&gt;@options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:queue&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;:print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:nowait&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:durable&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="vi"&gt;@type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="ss"&gt;:direct&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="消费消息"&gt;消费消息&lt;/h3&gt;
&lt;p&gt;启动 Sneakers Worker&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/workspace/hesheng/galaxy % &lt;span class="nv"&gt;WORKERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;GalaxyWorker rake sneakers:run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 Seakers 日志&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/workspace/hesheng/galaxy % &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; log/sneakers.log
018-03-14T02:35:01Z p-79500 t-oval8l8bg INFO: Heartbeat: running threads &lt;span class="o"&gt;[&lt;/span&gt;7]
2018-03-14T02:35:06Z p-79500 t-ovam12vfo INFO: GalaxyWorker::work msg &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"site"&lt;/span&gt;:&lt;span class="s2"&gt;"rubychina"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从日志来看，GalaxyWorker 成功收到了消息， {"site":"rubychina"}，因此，拿到消息后，可以根据业务对消息进行相应的处理。&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 14 Mar 2018 10:59:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/35230</link>
      <guid>https://ruby-china.org/topics/35230</guid>
    </item>
    <item>
      <title> 误用 find_each 引起的性能问题</title>
      <description>&lt;h2 id="each 方法"&gt;each 方法&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;SendLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# do something……&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Model.all.each 会使 Active Record 一次性取回整个数据表，为每条记录创建模型对象，并把整个模型对象数组保存在内存中。
当表的记录很大的时候，整个模型对象数组需要占用的空间可能会超过应用服务器的内存容量，导致应用或者服务器崩溃。&lt;/p&gt;
&lt;h2 id="find_each 方法"&gt;find_each 方法&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;SendLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# do something……&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;find_each 方法检索一批记录，然后逐一把每条记录作为模型传入块。在上面的例子中，find_each 方法取回 1000 条记录（find_each 和 find_in_batches 方法都默认一次检索 1000 条记录），然后逐一把每条记录作为模型传入块。这一过程会不断重复，直到完成所有记录的处理&lt;/p&gt;
&lt;h2 id="业务及应用场景"&gt;业务及应用场景&lt;/h2&gt;&lt;h3 id="数据表"&gt;数据表&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;数据记录大于 3000 万条&lt;/li&gt;
&lt;li&gt;为 record_date 和 user_id 创建了索引&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="查询"&gt;查询&lt;/h3&gt;
&lt;p&gt;查询语句样例：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;043&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;send_logs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SendLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"record_date &amp;gt;=? and record_date &amp;lt;=? and user_id in (?)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20170409&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20170508&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;043&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Shard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;slave1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;15.6&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="no"&gt;SELECT&lt;/span&gt; &lt;span class="no"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="sb"&gt;`send_logs`&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;20170409&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;20170508&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1732&lt;/span&gt; 

&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;051&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;052&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Shard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;slave1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="no"&gt;SendLog&lt;/span&gt; &lt;span class="no"&gt;Load&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;27.7&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="no"&gt;SELECT&lt;/span&gt;  &lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="sb"&gt;`send_logs`&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;20170409&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;20170508&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="no"&gt;ORDER&lt;/span&gt; &lt;span class="no"&gt;BY&lt;/span&gt; &lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` ASC LIMIT 1000
[Shard: slave1]  SendLog Load (61894.6ms)  SELECT  `&lt;/span&gt;&lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="sb"&gt;`.* FROM `&lt;/span&gt;&lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="sb"&gt;` WHERE (record_date &amp;gt;=20170409 and record_date &amp;lt;=20170508 and user_id in (1,2,3,4)) AND (`&lt;/span&gt;&lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="sb"&gt;`.`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` &amp;gt; 235181319)  ORDER BY `&lt;/span&gt;&lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="sb"&gt;`.`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` ASC LIMIT 1000
 =&amp;gt; nil 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上产生的 SQL 语句可以看出，find_each 每次 limit 1000 条记录，由于 send_logs 的记录数为 1732 条，所以  send_logs.find_each 将会产生 2 条 SQL 查询语句&lt;/p&gt;

&lt;p&gt;第一次 SQL 操作，执行时间，花费  27.7ms，而第二次查询操作耗时 &lt;strong&gt;61894.6ms&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="慢查询分析"&gt;慢查询分析&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;SendLog&lt;/span&gt; &lt;span class="no"&gt;Load&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;61894.6&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="no"&gt;SELECT&lt;/span&gt;  &lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="sb"&gt;`send_logs`&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;20170409&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;20170508&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="no"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` &amp;gt; 235181319)  ORDER BY `&lt;/span&gt;&lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="sb"&gt;`.`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` ASC LIMIT 1000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上耗时的 SQL，在前一条的基础上面，增加 AND (&lt;code&gt;send_logs&lt;/code&gt;.&lt;code&gt;id&lt;/code&gt; &amp;gt; 235181319) 的限制条件，用 explain 命令来查看 SQL 语句的执行情况，可以看到，该条查询没有用到索引，一次操作扫描了 1200 万条记录&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;explain&lt;/span&gt; &lt;span class="no"&gt;SELECT&lt;/span&gt;  &lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="sb"&gt;`send_logs`&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;20170409&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;20170508&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="no"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` &amp;gt; 245317804)  ORDER BY `&lt;/span&gt;&lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="sb"&gt;`.`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` ASC LIMIT 1000&lt;/span&gt;&lt;span class="se"&gt;\G&lt;/span&gt;&lt;span class="sb"&gt;;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: send_logs
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: 
         rows: 12233849
        Extra: Using where
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而第一条语句是可以用到索引的&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;explain&lt;/span&gt; &lt;span class="no"&gt;SELECT&lt;/span&gt;  &lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="sb"&gt;`send_logs`&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;20170409&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;record_date&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;20170508&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="no"&gt;ORDER&lt;/span&gt; &lt;span class="no"&gt;BY&lt;/span&gt; &lt;span class="sb"&gt;`send_logs`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;` ASC LIMIT 1000&lt;/span&gt;&lt;span class="se"&gt;\G&lt;/span&gt;&lt;span class="sb"&gt;;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: send_logs
         type: range
possible_keys: index_send_logs_on_user_id
          key: index_send_logs_on_user_id
      key_len: 5
          ref: 
         rows: 14292
        Extra: Using index condition; Using where; Using filesort
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际的业务场景中，根据条件查询出来的数据量，最多只有数千条，所以直接用 each 方法，取代 find_each 方法，这样就一次性把少量的数据加载到内存中，对记录进行访问时，提升系统性能。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;066&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ms&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;067&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;       &lt;span class="n"&gt;send_logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;06&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;       &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;06&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.196017324924469&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="总结及改进"&gt;总结及改进&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;find_each 生成的 SQL 语句，会忽略用户自己的:order 和 :limit 条件，固定用 ordey by &lt;code&gt;table&lt;/code&gt;.&lt;code&gt;id&lt;/code&gt; asc limit 1000&lt;/li&gt;
&lt;li&gt;find_each 方法用于大量记录的批处理，记录数量很大以至于不能一次加载到内存，比如需要遍历全表记做数据处理。&lt;/li&gt;
&lt;li&gt;当遇到慢查询的时候，用 explain 命令，查看是否索引命中&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>luolinae86</author>
      <pubDate>Tue, 09 May 2017 12:02:28 +0800</pubDate>
      <link>https://ruby-china.org/topics/32956</link>
      <guid>https://ruby-china.org/topics/32956</guid>
    </item>
    <item>
      <title>基于 Ubuntu 配置服务器、设定帐号、搭建 Ruby on Rails 环境</title>
      <description>&lt;p&gt;本文介绍开发者购买云服务器，得到公网 ip 地址以及 root 密码后，怎么从 0 到 1，配置服务器，帐号，以及安装 ruby on rails 环境&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;本文远程服务器版本 &lt;strong&gt;ubuntu 14.04&lt;/strong&gt;   本机 &lt;strong&gt;macbook pro&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="服务器及帐号配置"&gt;服务器及帐号配置&lt;/h3&gt;&lt;h4 id="实现本地无密码登陆"&gt;实现本地无密码登陆&lt;/h4&gt;&lt;h5 id="【1】从本地以root用户登陆远程服务器"&gt;【1】从本地以 root 用户登陆远程服务器&lt;/h5&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;luolin@MacBook-Pro:~/workspace/&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &lt;span class="nt"&gt;-l&lt;/span&gt; root 122.22.24.34
&lt;span class="c"&gt;#输入root用户的密码登陆&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="【2】生成服务器ssh相关文件"&gt;【2】生成服务器 ssh 相关文件&lt;/h5&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;root@iZ23ecuezr3Z:~# ssh-keygen
&lt;span class="c"&gt;#一路回车即可&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="【3】将本机加入服务器信任列表"&gt;【3】将本机加入服务器信任列表&lt;/h5&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;root@iZ23ecuezr3Z:~# vim ~/.ssh/authorized_keys
&lt;span class="c"&gt;#新起一行，将本机的 ~/.ssh/id_rsa.pub 文件内容追加到文件中&lt;/span&gt;
&lt;span class="c"&gt;#这样再次ssh登陆远程机器，就不用输入密码&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="创建开发帐号并配置权限"&gt;创建开发帐号并配置权限&lt;/h4&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;root@iZ23ecuezr3Z:~# adduser deployer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置 sudo 权限&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@iZ23ecuezr3Z:~# visudo
&lt;span class="c"&gt;#在文件的 root ALL=(ALL:ALL) ALL 下面增加一行&lt;/span&gt;
deployer &lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;ALL:ALL&lt;span class="o"&gt;)&lt;/span&gt; ALL
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="修改主机名称"&gt;修改主机名称&lt;/h4&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#编辑/etc.hostname  例如主机名为shenbiandev，注意不能有下划线，不能为shenbian_dev&lt;/span&gt;
root@iZ23ecuezr3Z:~# vim /etc/hostname
&lt;span class="c"&gt;#重启系统，永久生效&lt;/span&gt;
root@iZ23ecuezr3Z:~# reboot &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;span class="c"&gt;#退出重新登陆后，主机名变为：&lt;/span&gt;
root@shenbiandev:~#
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="修改ssh默认端口，限制root密码登陆，设置客户端掉链时间及最大连接数"&gt;修改 ssh 默认端口，限制 root 密码登陆，设置客户端掉链时间及最大连接数&lt;/h4&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;root@shenbiandev:~# vim /etc/ssh/sshd_config 
&lt;span class="c"&gt;#ssh 连接端口修改为2323&lt;/span&gt;
Port 2323
&lt;span class="c"&gt;#不允许用root直接登陆&lt;/span&gt;
PermitRootLogin no
&lt;span class="c"&gt;# 只允许通过key访问，不允许通过用户名和密码访问，确保安全&lt;/span&gt;
PubkeyAuthentication &lt;span class="nb"&gt;yes
&lt;/span&gt;PasswordAuthentication no
ClientAliveInterval 15
ClientAliveCountMax 45
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="安装防火墙"&gt;安装防火墙&lt;/h4&gt;
&lt;p&gt;ubuntu 默认的防火墙是 UFW&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#安装 &lt;/span&gt;
root@shenbiandev:~# apt-get &lt;span class="nb"&gt;install &lt;/span&gt;ufw
&lt;span class="c"&gt;#查看可用命令&lt;/span&gt;
root@shenbiandev:~# ufw &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;span class="c"&gt;#启动防火墙&lt;/span&gt;
root@shenbiandev:~# ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;span class="c"&gt;#开放2323端口&lt;/span&gt;
root@shenbiandev:~# ufw allow 2323
&lt;span class="c"&gt;#重启ssh服务&lt;/span&gt;
root@shenbiandev:~# service ssh restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;至此，就不能再通过 ssh -l root ip 的形式登陆服务器，而只能用开发帐号从 2323 端口登陆&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;luolin@MacBook-Pro:~/workspace&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &lt;span class="nt"&gt;-l&lt;/span&gt; deployer ip &lt;span class="nt"&gt;-p&lt;/span&gt; 2323
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;至此，服务器的帐号及登陆设置完成下面安装 ruby 及 rails 环境&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="安装RVM"&gt;安装 RVM&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;curl
deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://get.rvm.io | bash &lt;span class="nt"&gt;-s&lt;/span&gt; stable
deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.rvm/scripts/rvm
deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;rvm &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="安装Ruby"&gt;安装 Ruby&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;rvm list known
&lt;span class="c"&gt;#安装最新的版本2.3.0&lt;/span&gt;
deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;rvm &lt;span class="nb"&gt;install &lt;/span&gt;2.3.0
deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;rvm 2.3.0 &lt;span class="nt"&gt;--default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="安装Rails"&gt;安装 Rails&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;根据自己需要的版本，安装Rails
deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;rails &lt;span class="nt"&gt;--version&lt;/span&gt; 5.0.0.beta1
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="安装Rails"&gt;安装 Rails&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;安装自己所需的rails版本
deployer@shenbiandev:~&lt;span class="nv"&gt;$ &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;rails &lt;span class="nt"&gt;-v&lt;/span&gt; 5.0.0.beta1 &lt;span class="nt"&gt;--pre&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="制作自己的镜像"&gt;制作自己的镜像&lt;/h3&gt;
&lt;p&gt;当环境设置完成后，可以在云提供商端，将自己的环境，制作成一个镜像，后面当自己还需要类似环境时，购买时选择自己制作的镜像，
这样新分配的服务器，就和以上的配置完全一致了，从而避免 2 次配置，提高工作效率。&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Sun, 22 May 2016 16:28:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/30086</link>
      <guid>https://ruby-china.org/topics/30086</guid>
    </item>
    <item>
      <title>Rails + AngulaJs + Pusher 实现浏览器实时刷新</title>
      <description>&lt;h4 id="需求背景描述"&gt;需求背景描述&lt;/h4&gt;&lt;h5 id="技术栈"&gt;技术栈&lt;/h5&gt;
&lt;p&gt;鄙人所在公司，主要业务做眼底图象医学量化识别，技术栈包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Rails &lt;/li&gt;
&lt;li&gt;sidekiq&lt;/li&gt;
&lt;li&gt;redis&lt;/li&gt;
&lt;li&gt; Mysql&lt;/li&gt;
&lt;li&gt; AngularJs + jQuery&lt;/li&gt;
&lt;li&gt; Matlab&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="业务系统"&gt;业务系统&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;业务系统，用 Rails+AngularJs 实现&lt;/li&gt;
&lt;li&gt;算法系统，用 Matlab 实现&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="业务流程"&gt;业务流程&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;医院通过业务系统上传眼底图片，组件包括：

&lt;ul&gt;
&lt;li&gt; jQuery 异步上传组件 &amp;gt;  &lt;a href="https://blueimp.github.io/jQuery-File-Upload/" rel="nofollow" target="_blank"&gt;https://blueimp.github.io/jQuery-File-Upload/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; 阿里云上传组件  &amp;gt;  &lt;a href="https://github.com/huacnlee/carrierwave-aliyun" rel="nofollow" target="_blank"&gt;https://github.com/huacnlee/carrierwave-aliyun&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;算法系统对图片进行预处理，生成医学所需要的量化处理结果（异步处理）&lt;/li&gt;
&lt;li&gt;在业务系统中人工对量化不准确的进行手工修正&lt;/li&gt;
&lt;li&gt;算法系统接收修改请求，并返回修改后结果（异步处理）&lt;/li&gt;
&lt;li&gt;业务系统后台，通知前端浏览器主动刷新，并显示修正后的量化结果&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id="浏览器数据刷新技术选型"&gt;浏览器数据刷新技术选型&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Polling angularJs 通过固定的时间片轮流向 server 发起 http 请求，加载最新的数据，缺点&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;存在延时&lt;/li&gt;
&lt;li&gt;不断的 http 请求，消耗服务器系统资源&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pusher，浏览器在特定的通道上注册特定的事件，服务器在特定的通道上面触发特定事件，
从而完成 server 端到 client 端的实时通知，优点&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;实时通知&lt;/li&gt;
&lt;li&gt;服务器端性能消耗少&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="代码展示"&gt;代码展示&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;sever 端&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;添加 pusher gem&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/pusher/pusher-http-ruby" rel="nofollow" target="_blank"&gt;https://github.com/pusher/pusher-http-ruby&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;添加配置文件 config/initailizer/pusher.rb&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'pusher'&lt;/span&gt;

&lt;span class="no"&gt;Pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;app_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'***************'&lt;/span&gt;
&lt;span class="no"&gt;Pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'*******************'&lt;/span&gt;
&lt;span class="no"&gt;Pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'*******************'&lt;/span&gt;
&lt;span class="no"&gt;Pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;
&lt;span class="no"&gt;Pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;触发事件通知&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'channel_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'event_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s1"&gt;'hello world'&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;client 端&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;下载 angular-pusher.min.js 库&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/doowb/angular-pusher/blob/master/angular-pusher.min.js" rel="nofollow" target="_blank"&gt;https://github.com/doowb/angular-pusher/blob/master/angular-pusher.min.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;注册事件&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//注册pusher事件&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pusher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pusher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_APP_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channel_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;event_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//更新picUrl，从而主angularJs重新刷新图片&lt;/span&gt;
    &lt;span class="nx"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;picUrl&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?decache=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="问题及求助"&gt;问题及求助&lt;/h4&gt;
&lt;p&gt;目前业务系统和算法系统，是两个独立部署的系统，其中 Matlab 是编译成可执行文件的形式运行
业务系统通知算法系统，都是通过异步写文件的形式，Matlab 从文件中读取指定，并执行相应的
算法，然后业务系统得自己检测结果文件，处理业务逻辑，并上传。&lt;/p&gt;

&lt;p&gt;业务系统和算法系统，只能算得上单工通信，算法部分之前研究过用 C++ 语言提供 api 接口给业务系统实现双工，
但该方式没有能够调试成功，&lt;strong&gt;论坛里面是否有人之前做过用 Matlab 提供 REST API 接口这方面的研究，
如果有的，请给出您宝贵的建议或者 demo，谢谢&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;####参考文献&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://blog.pusher.com/making-angular-js-realtime-with-pusher/" rel="nofollow" target="_blank"&gt;https://blog.pusher.com/making-angular-js-realtime-with-pusher/&lt;/a&gt;
&lt;a href="https://pusher.com/tutorials/realtime-notifications" rel="nofollow" target="_blank"&gt;https://pusher.com/tutorials/realtime-notifications&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>luolinae86</author>
      <pubDate>Tue, 29 Mar 2016 10:42:59 +0800</pubDate>
      <link>https://ruby-china.org/topics/29487</link>
      <guid>https://ruby-china.org/topics/29487</guid>
    </item>
    <item>
      <title>Basecamp 3 发布了 免费版本再次回归</title>
      <description>&lt;p&gt;&lt;a href="/DHH" class="user-mention" title="@DHH"&gt;&lt;i&gt;@&lt;/i&gt;DHH&lt;/a&gt;的推文发布了 Basecamp 3 发布的消息&lt;/p&gt;

&lt;p&gt;详情&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://signalvnoise.com/posts/3968-launch-basecamp-3" rel="nofollow" target="_blank"&gt;https://signalvnoise.com/posts/3968-launch-basecamp-3&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;免费版本的 Basecamp 也回来了，可以从官网注册个人帐户&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://basecamp.com/" rel="nofollow" target="_blank"&gt;https://basecamp.com/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="/ruby" class="user-mention" title="@ruby"&gt;&lt;i&gt;@&lt;/i&gt;ruby&lt;/a&gt; on rails 官网推文&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;First production app running Action Cable, Turbolinks 5, and Rails 5.0.alpha in the wild is live: Basecamp 3.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Basecamp 3.0 是第一个在正式环境中，应用 Action Cable, Turbolinks 5, 以及 Rails 5.0 alpha 版本的产品&lt;/p&gt;

&lt;p&gt;其它不多说，各位客官还是先自己注册一个帐号，玩起来吧。&lt;/p&gt;

&lt;p&gt;也期待 tower 产品的跟进 &lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt;&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 04 Nov 2015 10:21:23 +0800</pubDate>
      <link>https://ruby-china.org/topics/27941</link>
      <guid>https://ruby-china.org/topics/27941</guid>
    </item>
    <item>
      <title>存在内存泄露的 Gem 列表</title>
      <description>&lt;p&gt;请大家检查下 Gemfile.lock，若在使用如下版本的 gem 包，那么请及时更新&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;therubyracer &amp;lt; 0.12.2&lt;/li&gt;
&lt;li&gt;sidekiq &amp;lt; 3.5.1&lt;/li&gt;
&lt;li&gt;celluloid &amp;gt; 0.16.0, &amp;lt; 0.17.2&lt;/li&gt;
&lt;li&gt;zipruby &amp;lt;= 0.3.6&lt;/li&gt;
&lt;li&gt;redcarpet &amp;lt; 3.3.3&lt;/li&gt;
&lt;li&gt;grape &amp;lt; 0.2.5&lt;/li&gt;
&lt;li&gt;oj &amp;lt; 2.12.4&lt;/li&gt;
&lt;li&gt;newrelic_rpm &amp;lt; 3.9.8&lt;/li&gt;
&lt;li&gt;csspool &amp;lt; 4.0.3&lt;/li&gt;
&lt;li&gt;axlsx&lt;/li&gt;
&lt;li&gt;delayed_job &amp;gt;= 4.06&lt;/li&gt;
&lt;li&gt;ruby-pinyin &amp;lt;= 0.4.8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;楼下的客官，如果发现其它有内存泄露的 gem 包，&lt;strong&gt;请跟帖，并给出连接&lt;/strong&gt;，我来更新列表，谢谢。&lt;/p&gt;

&lt;p&gt;引用自&lt;strong&gt;@ruby_news&lt;/strong&gt;的推文&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/ruby_news/status/656559603698827264" rel="nofollow" target="_blank"&gt;https://twitter.com/ruby_news/status/656559603698827264&lt;/a&gt;
&lt;a href="https://github.com/ASoftCo/leaky-gems" rel="nofollow" target="_blank"&gt;https://github.com/ASoftCo/leaky-gems&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 21 Oct 2015 09:46:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/27761</link>
      <guid>https://ruby-china.org/topics/27761</guid>
    </item>
    <item>
      <title>利用数组的 &amp; 操作，精减代码</title>
      <description>&lt;p&gt;&lt;strong&gt;精减前&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;#do something&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;精减后&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;any?&lt;/span&gt;
&lt;span class="c1"&gt;#do something&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数组对象的 &lt;strong&gt;&amp;amp;&lt;/strong&gt;  操作，是求数组的交集
因此，需要判断在某个大的集合中，是否包含小集合中的一个或者多个时，
用 &lt;strong&gt;&amp;amp;&lt;/strong&gt; 操作取代 &lt;strong&gt;||&lt;/strong&gt; 操作可以精减代码&lt;/p&gt;

&lt;p&gt;数组中，值得注意的还有 &lt;strong&gt;-&lt;/strong&gt; 操作，&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;#[1]&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;#[4]&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;操作得到的数组是在&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;中存在&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;但&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;中不存在的元素&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;反之亦然&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luolinae86</author>
      <pubDate>Mon, 21 Sep 2015 16:56:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/27421</link>
      <guid>https://ruby-china.org/topics/27421</guid>
    </item>
    <item>
      <title> Rails 中的 blank? and present?</title>
      <description>&lt;h4 id="以下各值在 Rails 程序里都看作 blank，而 present? 方法等同于 !blank?"&gt;以下各值在 Rails 程序里都看作 blank，而 present? 方法等同于 !blank?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;nil 和 false，&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;只包含空白的字符串 (参照下文注释),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;空的数组和散列表&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;任何其他能响应 empty? 方法且为空的对象。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;注意这里没有提到数字。通常来说，0 和 0.0 都不是 blank&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="测试结果"&gt;测试结果&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p451&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;01&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; 
&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p451&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;020&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; 
&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p451&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;021&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; 
&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p451&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;022&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; 
&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p451&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;023&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt; 
&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p451&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;024&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;引用自 &lt;a href="http://guides.ruby-china.org/active_support_core_extensions.html" rel="nofollow" target="_blank"&gt;http://guides.ruby-china.org/active_support_core_extensions.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 16 Sep 2015 10:17:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/27352</link>
      <guid>https://ruby-china.org/topics/27352</guid>
    </item>
    <item>
      <title>has_and_belongs_to_many 数据验证方法 及 错误提示</title>
      <description>&lt;h4 id="前言"&gt;前言&lt;/h4&gt;
&lt;p&gt;数据验证能确保只有合法的数据才会存入数据库
数据存入数据库之前的验证方法&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; 模型中做验证（相对而言最有保障）&lt;/li&gt;
&lt;li&gt; 数据库内建的约束&lt;/li&gt;
&lt;li&gt; 客户端验证&lt;/li&gt;
&lt;li&gt; 控制器层验证&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;本文重点分享一下，多对多关联模型层的数据验证方法，以及友好的用户提醒&lt;/p&gt;
&lt;h4 id="验证场景"&gt;验证场景&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;模型层&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_and_belongs_to_many&lt;/span&gt; &lt;span class="ss"&gt;:roles&lt;/span&gt;
  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:roles&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用户 (user) 和角色 (role)，多对多，即 &lt;strong&gt;has_and_belongs_to_many&lt;/strong&gt; 的关系&lt;/p&gt;

&lt;p&gt;系统要求，系统管理员在创建用户时，必须指明用户的角色，否则不能创建用户，系统需要给出友好提醒&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;控制器&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role_ids&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:role_ids&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="验证方式"&gt;验证方式&lt;/h3&gt;&lt;h4 id="In Rails 3.2"&gt;In Rails 3.2&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_and_belongs_to_many&lt;/span&gt; &lt;span class="ss"&gt;:roles&lt;/span&gt;
  &lt;span class="n"&gt;validate&lt;/span&gt; &lt;span class="ss"&gt;:minimum_one_role&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;minimum_one_role&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'请至少要选择一个角色'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="In Rails 4"&gt;In Rails 4&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_and_belongs_to_many&lt;/span&gt; &lt;span class="ss"&gt;:roles&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:roles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;presence: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="出错提醒"&gt;出错提醒&lt;/h3&gt;&lt;h4 id="创建用户角色界面"&gt;创建用户角色界面&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/a09946783334adc8a079aad55faa5ebd.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;此时，如果管理员不勾选用户角色为“研究者” ，“读片员“中的一个或多个&lt;/p&gt;

&lt;p&gt;则调用 &lt;strong&gt;User.create&lt;/strong&gt; 方法时，模型层对 roles 的数据验证出错，并将出错信息添加到 errors 错误集合中&lt;/p&gt;
&lt;h4 id="显示错误信息"&gt;显示错误信息&lt;/h4&gt;&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vi"&gt;@user.blank&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@user.errors.any&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="vi"&gt;@user.errors.each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kp"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"error_message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/c8a0dec8a1d0fff751be4fdf272e3d71.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h4 id="设置错误提醒的css 样式为红色背景"&gt;设置错误提醒的 css 样式为红色背景&lt;/h4&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.error_message{
  background-color: red;
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 09 Sep 2015 16:51:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/27254</link>
      <guid>https://ruby-china.org/topics/27254</guid>
    </item>
    <item>
      <title>利用 Mina 自动部署 Rails + Sidekiq + Unicorn</title>
      <description>&lt;p&gt;社区上面关于自动部署的文章比较完整和齐全了，在此，我仅将自己最近用 mina 部署 Rails+sidekiq+unicorn 的整个过程，做一个总结，希望对新手做一个指引，也抛砖引玉，希望更多高手发表自己的部署经验，共勉。&lt;/p&gt;
&lt;h3 id="部署方案选择"&gt;部署方案选择&lt;/h3&gt;
&lt;p&gt;Rails 自动部署，主流的方案有：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capistrano&lt;/li&gt;
&lt;li&gt;Mina&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;刚开始选择了 capistrano，感觉比较折腾，最终选择了 mina。最后发现，选择 mina 是值的，特别是配合 mina-sidekiq，和 mina-unicorn，让整个部署更加简洁，高效。&lt;/p&gt;
&lt;h3 id="部署步骤"&gt;部署步骤&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Mina 地址&lt;a href="https://github.com/mina-deploy/mina" rel="nofollow" target="_blank"&gt;https://github.com/mina-deploy/mina&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="引入mina gem"&gt;引入 mina gem&lt;/h4&gt;
&lt;p&gt;在 Gemfile 中增加：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'mina'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="初始化(mina init)"&gt;初始化 (mina init)&lt;/h4&gt;
&lt;p&gt;在相应的 Rails 工作目录，执行&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mina init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;mina init 命令会在 config 目录生成一个默认的配置文件 deploy.rb&lt;/p&gt;
&lt;h4 id="引入mina-sidekiq"&gt;引入 mina-sidekiq&lt;/h4&gt;
&lt;p&gt;项目中，运用到了 sidekiq 做异步队列：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/Mic92/mina-sidekiq/blob/master/README.md" rel="nofollow" target="_blank"&gt;https://github.com/Mic92/mina-sidekiq/blob/master/README.md&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Gemfile 中增加&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'mina-sidekiq'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="引入 mina-unicorn"&gt;引入 mina-unicorn&lt;/h4&gt;
&lt;p&gt;应用服务器用的 unicorn，使用 mina-unicorn，可以非常方便完成进程的启，停，重启&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/scarfacedeb/mina-unicorn/blob/master/lib/mina/unicorn/tasks.rb" rel="nofollow" target="_blank"&gt;https://github.com/scarfacedeb/mina-unicorn/blob/master/lib/mina/unicorn/tasks.rb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Gemfile 中增加：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'mina-unicorn'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注：以下配置都是修改 config/deploy.rb 文件&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="配置目标主机"&gt;配置目标主机&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*.*.*.*'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:deploy_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/data/project/science_read'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'deployer'&lt;/span&gt;    
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'3118'&lt;/span&gt;    
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:forward_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：domain 为目标主机 IP，deploy_to 为目标主机的部署路径，user 为用户名，port 为 ssh 的端口号。
注：请将自动部署机器的~/.ssh/id_rsa.pub，放置到目标机器的~/.ssh/authorized_keys 列表里面，从而完成自动登陆&lt;/p&gt;
&lt;h4 id="设置git地址"&gt;设置 git 地址&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'git@git.aliyun.tata.cn.com:hesheng/science_read.git'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'master'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="设置sidekiq和unicorn进程pid保存地址"&gt;设置 sidekiq 和 unicorn 进程 pid 保存地址&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:sidekiq_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/sidekiq.pid"&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/unicorn.pid"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="设置rvm的安装路径及ruby版本"&gt;设置 rvm 的安装路径及 ruby 版本&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:rvm_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/usr/local/rvm/bin/rvm'&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rvm:use[ruby-2.0.0@default]'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="设置共享文件或目录"&gt;设置共享文件或目录&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:shared_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'config/database.yml'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'config/yetting.yml'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'config/symmetric-encryption.yml'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'log'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上设置了 log 目录，以及 database.yml,yetting.yml,symmetric-encryption.yml 为所有版本共享&lt;/p&gt;
&lt;h4 id="设置目标主机目录及文件 (mina setup)"&gt;设置目标主机目录及文件 (mina setup)&lt;/h4&gt;
&lt;p&gt;以下是执行 mina setup 命令时，在远程目录机执行的创建目录或者文件的操作&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:setup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/tmp/sockets/"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/tmp/pids/"]&lt;/span&gt;

  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/log"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config"]&lt;/span&gt;

  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/database.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/yetting.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/symmetric-encryption.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue&lt;/span&gt;  &lt;span class="sx"&gt;%[echo "-----&amp;gt; Be sure to edit '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/database.yml','yetting.yml', 'symmetric-encryption.yml'."]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="增加部署命令(mina deploy)"&gt;增加部署命令 (mina deploy)&lt;/h4&gt;
&lt;p&gt;以下是执行 mina deploy 命令时，执行的任务操作，是整个远程部署的核心&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Deploys the current version to the server."&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:deploy&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="ss"&gt;:before_hook&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Put things to run locally before ssh&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;deploy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'git:clone'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'deploy:link_shared_paths'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'bundle:install'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rails:db_migrate'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rails:assets_precompile'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'deploy:cleanup'&lt;/span&gt;

    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="ss"&gt;:launch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;# sidekiq stop accepting new workers&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'sidekiq:quiet'&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'sidekiq:restart'&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'unicorn:restart'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;             
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;task:deploy，首先从 repository 的 branch 中 clone 一份代码到 deploy_to 目录，然后生成连接目录及文件，执行 bundle, db_migrate,assets_precompile 命令
，最后会执行 launch，里面的 sidekiq 异步任务的重启，以及 unicorn 进程重启。&lt;/p&gt;
&lt;h4 id="修改共享文件"&gt;修改共享文件&lt;/h4&gt;
&lt;p&gt;编辑，database.yml,yetting.yml，以及 symmetric-encryption.yml 文件，以使其符合正式部署的需求。&lt;/p&gt;
&lt;h2 id="修改config/unicron配置文件"&gt;修改 config/unicron 配置文件&lt;/h2&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="s2"&gt;"/data/project/science_read/tmp/sockets/unicorn.sock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:backlog&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="s2"&gt;"/data/project/science_read/tmp/pids/unicorn.pid"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之所以这样修改，是因为，自动部署后，APP_HOME = Rails.root 会从未部署时候的/data/project/science_read/变成/data/project/science_read/current&lt;/p&gt;
&lt;h4 id="执行mina setup远程部署命令"&gt;执行 mina setup 远程部署命令&lt;/h4&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mina deploy
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="设置crontab 定时远程部署"&gt;设置 crontab 定时远程部署&lt;/h4&gt;
&lt;p&gt;在实际的项目中，可能会定时完成自动部署，比如每小时的 0 分钟时部署一次，crontab 任务&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 * * * * cd /data/project/mina_do_not_remove/science_read &amp;amp;&amp;amp; mina deploy
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="整个config/deploy.rb部署脚本"&gt;整个 config/deploy.rb 部署脚本&lt;/h4&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/bundler'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/rails'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/git'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/rvm'&lt;/span&gt;    
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mina/unicorn'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"mina_sidekiq/tasks"&lt;/span&gt;

&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*.*.*.*'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:deploy_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/data/project/science_read'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'deployer'&lt;/span&gt;         
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'3118'&lt;/span&gt;            
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:forward_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;

&lt;span class="c1"&gt;#设置git地址及分支&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'git@git.aliyun.zeta.cn.com:hesheng/science_read.git'&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:branch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'master'&lt;/span&gt;

&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:rvm_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/usr/local/rvm/bin/rvm'&lt;/span&gt;

&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:shared_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'config/database.yml'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'config/yetting.yml'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'config/symmetric-encryption.yml'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'log'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;#设置sidekiq的进程保存地址&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:sidekiq_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/sidekiq.pid"&lt;/span&gt;


&lt;span class="c1"&gt;#设置unicorn pid 及 进程启动环境&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/pids/unicorn.pid"&lt;/span&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:unicorn_env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rvm:use[ruby-2.0.0@default]'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:setup&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# unicorn and sidekiq needs a place to store its pid file&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/tmp/sockets/"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/tmp/pids/"]&lt;/span&gt;

  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/log"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[mkdir -p "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config"]&lt;/span&gt;

  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/database.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/yetting.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue!&lt;/span&gt; &lt;span class="sx"&gt;%[touch "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/symmetric-encryption.yml"]&lt;/span&gt;
  &lt;span class="n"&gt;queue&lt;/span&gt;  &lt;span class="sx"&gt;%[echo "-----&amp;gt; Be sure to edit '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;deploy_to&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;shared_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;/config/database.yml','yetting.yml', 'symmetric-encryption.yml'."]&lt;/span&gt;

  &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="sx"&gt;%[
    repo_host=`echo $repo | sed -e 's/.*@//g' -e 's/:.*//g'` &amp;amp;&amp;amp;
    repo_port=`echo $repo | grep -o ':[0-9]*' | sed -e 's/://g'` &amp;amp;&amp;amp;
    if [ -z "${repo_port}" ]; then repo_port=22; fi ]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Deploys the current version to the server."&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:deploy&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="ss"&gt;:before_hook&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Put things to run locally before ssh&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;deploy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'git:clone'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'deploy:link_shared_paths'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'bundle:install'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rails:db_migrate'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'rails:assets_precompile'&lt;/span&gt;
    &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'deploy:cleanup'&lt;/span&gt;

    &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="ss"&gt;:launch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="c1"&gt;# sidekiq stop accepting new workers&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'sidekiq:quiet'&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'sidekiq:restart'&lt;/span&gt;
      &lt;span class="n"&gt;invoke&lt;/span&gt; &lt;span class="ss"&gt;:'unicorn:restart'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luolinae86</author>
      <pubDate>Mon, 27 Jul 2015 16:46:03 +0800</pubDate>
      <link>https://ruby-china.org/topics/26661</link>
      <guid>https://ruby-china.org/topics/26661</guid>
    </item>
    <item>
      <title>请问，Ruby 怎么弹出文件夹，并选择里面的文件读取？</title>
      <description>&lt;p&gt;目前，想用 ruby，实现弹出系统的文件夹，然后选择里面的文件进行读取操作：
比如在 window 下面，弹出我的电脑
在 mac 下面弹出 Finder，求各位高人指点，多谢！&lt;/p&gt;</description>
      <author>luolinae86</author>
      <pubDate>Wed, 12 Mar 2014 23:48:05 +0800</pubDate>
      <link>https://ruby-china.org/topics/17841</link>
      <guid>https://ruby-china.org/topics/17841</guid>
    </item>
  </channel>
</rss>
