Sidekiq アンチパターンのまとめ
Sidekiq アンチパターン
業務でsidekiqを利用するケースがあったのですが、sidekiqのアンチパターンについて知らなかったのでまとめました。
1. 命名規則について
ワーカーの名前は後から変更するのは後から変更するのは大変です。
ワーカーの命名規則をつけるときは動作を表すようにしましょう。
BAD
1. WebhookWorker 2. ImportWorker
この命名規則はどうでしょうか?
1はwebhookで何をするのかの情報が不十分です。
2は何をimportするのかの情報が不十分です。
GOOD
1. WebhookNotificationWorker 2. CrewImportWorker
2. 非同期処理内の例外握り潰し
def perform(arg) # something to do rescue => e logger.error "#{e.class}: #{e.message}" end
非同期の中で例外握りつぶしをするのはNGです。
perform 実行中にいかなる例外が発生しようとも rescue 節でキャッチしてしまうので、 perform を呼び出した worker はジョブが成功したものとみなしてしまいます。
つまり、失敗したことに気づかない状態になってしまいます。
def perform(arg) # something to do rescue => e raise '処理に失敗しました><' end
resucueの中で発生した例外を RuntimeError で上書きしてしまうと。
performの中でどのような例外が発生したか、わからなくなってしまうのでこちらもNGです。
def perform(arg) # something to do rescue => e 1 / Random.rand(2) # 50% chance to raise ZeroDivisionError raise e end
resucueの中で例外が発生し得る処理を記述するのもNGです。
rescueの中では例外が発生すると、rescueの意味がなくなってしまいます。
引数について
performの引数を実装途中で変更するのは非常に危険です。
class WebhookWorker include Sidekiq::Worker def perform(url, channel, message) payload = {channel: channel, message: message} RestClient.post(url, payload.to_json) end end
もし途中でWebhook パラメータを追加/変更したい場合に単純にワーカーが受け取れる引数を増やしたらどうなるでしょうか?
class WebhookWorker include Sidekiq::Worker def perform(url, channel, username, message) payload = {channel: channel, message: message, username: username} RestClient.post(url, payload.to_json) end end
Sidekiq ではジョブを予約した時の変数との対応は実行時に考慮してもらえないので思わぬトラブルを招きます。
WebhookWorker.perform_async('https://hooks.example.com/T00000000/XXXXX', 'general', 'hello, webhooks!')
このように引数の順序がメチャクチャになってしまいます
url = 'https://hooks.example.com/T00000000/XXXXX' channel = 'general' username = 'hello, webhooks! message = nil
参考
ActiveRecord::Base.connected_toの利用方法
ActiveRecord::Base.connected_toの利用方法
今の現場でActiveRecord::Base.connected_toを利用した実装をしており、初めてみた書き方だったのでメモを残す。
データベースのルールを明示的に指定することが出来る
ActiveRecord::Base.connected_to(role: :writing) do Dog.create! # 書き込みコネクションで書き込み成功 end ActiveRecord::Base.connected_to(role: :reading) do Dog.create! # 読み込みコネクションなのでエラー発生 end ActiveRecord::Base.connected_to(role: :unknown_role) do # 不明コネクションでエラー発生 end
参考
Rails.application.config_forで設定ファイル全体を読み込む方法
Rails::Application.config_forを使うと、設定ファイル全体を読み込むことができます。
例)
Rails.application.config_for(:for)
config_for(:for)とする事によって、config/foo.ymlに設定された内容を、そのまま定義することができます。
config/foo.ymlの内容
default: &default api: "https://stg.tsite.jp/hogehoge"
出力
pry> Rails.application.config_for(:foo) => {:api=>"https://stg.tsite.jp/hogehoge"}
config_for(:for)とする事によって、config/foo.ymlに設定された内容を、そのまま定義することができます'
参考:
Ruby on Rails: Rails標準の`config_for`を使ってカスタム設定を管理する⚙ - Madogiwa Blog
Rubyの条件分岐判定方法
Rubyの条件分岐判定方法
Rubyの条件判定は癖があるのでメモ残す。
Rubyの条件分岐は他のプログラミング言語同様に条件式が成立する時に返される「true」は真として扱われます。 また成立しなかった時に返される「false」は偽として扱われます。
falseとnilは偽 falseとnil以外は全て真
実は「false」と「nil」だけが偽となり、それ以外は全て「真」となります。「true」は「false」でも「nil」でもありませんので結果的に真となっています。
falseとnil以外は全て真なので、falseとnil以外の値が入れば全てtrueになると覚えておくと良いかもです。
# 全ての値とtrueそのものは真 1 2 3 [1, 2, 3] 'apple' '' true # falseとnilは偽 false nil
sidekiqの使い方備忘録
sidekiqの使い方備忘録
仕事でsidekiq利用する機会があったので使い方の備忘録を残す(自分用)
sidekiqとは?
Simple, efficient background processing for Ruby. Sidekiq uses threads to handle many jobs at the same time in the same process. It does not require Rails but will integrate tightly with Rails to make background processing dead simple.
バックグラウンドプロセス効率化することができる。 Railsを利用して利用するケースが多い、マルチスレッド処理ジョブを同一スレッドで処理することが可能。
sidekiq管理画面
バックグランドで処理されているジョブを管理画面から確認することが可能です。
Sidekiqには管理画面があり、routes.rbに以下のコードを記述すると実装できます。
require 'sidekiq/web' mount Sidekiq::Web, at: "/sidekiq"
http://localhost:3000/sidekiqにアクセスすると、管理画面に飛ぶことができます。
下記のようなエラーになる場合はRedisの設定ができていない可能性が高いです、sidekiqをローカルで利用する方法を参照してredisをインストールして起動すればエラーが消えるはずです。
sidekiqをローカルで利用する方法
redisインストール(Mac OS)
brew install redis
redis起動
brew services start redis
redis終了
brew services stop redis
sidekiqの利用方法
config以下に書いた設定コマンドを、以下のコマンドを実行します
bundle exec sidekiq -C config/sidekiq.yml
参考サイト
【Ruby on Rails】sidekiqの導入手順(ローカル、Heroku、AWS EC2、Docker、Capistrano) - Qiita
macOS に Redis を Homebrew でインストールして brew services で起動する - Qiita
【Rails】更新系メソッドまとめ
【Rails】更新系メソッドまとめ
すでにテーブルに保存されているデータを、新しい情報に更新するメソッドに関してまとめてみました。 自分用備忘録です。
updateメソッド
user = User.create(name: 'Taro', age: 15) # 成功 user.update(name: 'Taro') # => true # 失敗 user.update(name: nil) # => false
更新に成功したら、true返却 失敗したら、false返却
update!
user = User.create(name: 'Taro', age: 15) # 成功 user.update!(name: 'Taro') # => true # 失敗 user.update!(name: nil) # ActiveRecord::RecordInvalid (Validation failed: Name can't be blank)
updateとupdate!メソッドの違いは、結果の返し方が異なります。 updateの場合、保存の成否をtrueかfalseで返します。それに対してupdate!は保存に失敗したときに例外を返します。
update_attributeメソッド
@item.update_attribute(:num, 100)
update_attributeの実行時は、バリデーションのチェックがされないため、特別な理由がある場合以外は使用しないことが好ましい。
update_attributesメソッド
update_attributesはupdateのエイリアスメソッド(別名)なので、動作は全く同じ。
update_all
Item.update_all( num: 1)
update_allは、レコードの全ての値を一括で変更できるメソッド。 このような記述で、Itemsテーブルの全てのレコードのnumカラムの値を1に変更することができる。
ポスグレの初期化で詰まった話
DBをUTF-8で初期化しようとして下記のコマンドを入力
initdb /usr/local/var/postgres -E utf8
すると下記のようなエラーに遭遇
The files belonging to this database system will be owned by user "inouehiroki". This user must also own the server process. The database cluster will be initialized with locale "ja_JP.UTF-8". initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8" The default text search configuration will be set to "simple". Data page checksums are disabled. creating directory /usr/local/var/postgres ... initdb: error: could not create directory "/usr/local/var": Permission denied
perimissionエラーぽい。 この記事を参考にsudo権限で755(読み出せて、書き込めて、実行可能)権限を付与するようにしてみた。
すると下記のエラーに遭遇
✗ sudo mkdir /usr/local/var/postgres mkdir: /usr/local/var: No such file or directory
そもそも/usr/local/varが存在しないということなので、/usr/local/varを作成した後に権限付与する。
sudo mkdir /usr/local/var sudo mkdir /usr/local/var/postgres sudo chmod 775 /usr/local/var/postgres sudo chown ユーザー名 /usr/local/var/postgres
この後にもう一度initdb /usr/local/var/postgres -E utf8
を実施すると上手くいった
➜ local initdb /usr/local/var/postgres -E utf8 The files belonging to this database system will be owned by user "inouehiroki". This user must also own the server process. The database cluster will be initialized with locale "ja_JP.UTF-8". initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8" The default text search configuration will be set to "simple". Data page checksums are disabled. fixing permissions on existing directory /usr/local/var/postgres ... ok creating subdirectories ... ok selecting dynamic shared memory implementation ... posix selecting default max_connections ... 100 selecting default shared_buffers ... 128MB selecting default time zone ... Asia/Tokyo creating configuration files ... ok running bootstrap script ... ok performing post-bootstrap initialization ... ok syncing data to disk ... ok initdb: warning: enabling "trust" authentication for local connections You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. Success. You can now start the database server using: pg_ctl -D /usr/local/var/postgres -l logfile start