Rails でどこでも after_commit したい話

この記事は裏freee developers Advent Calendar 2018の16日目の記事です。 裏感なく普通にtips的な内容です。


ありがち?なバグ

かなり大雑把に表現すると↓のようなコードがありました。 do_something1 で新しく Model を作ったり更新したりしたあと、最終的な状態に基づいてメールを送信するという具合です(記事中の Model という言葉は ActiveRecord で表現される app/models 以下のやつらを指します)。 send_email は内部で ResqueMailer に処理を投げています。 do_something1 の部分で操作した Model をidベースで Mailer に渡し、Mailer 側ではidを使って取得するようになっています。

1
2
3
4
5
6
7
8
9
10
11
class Hoge
def exec
ActiveRecord::Base.transaction do
do_something1
send_email(model.id)
do_something2
end
end
end

Hoge.new.exec

do_something2 の処理が完了する前(=トランザクションがコミットされる前)に Mailer の処理が動いてしまうと、古い状態の Model が見えてしまったり、存在しない Model を取得しようとしてエラーになってしまいます。

ちょいちょい発生していたエラーを追っていたら、以上のような構造になっていました。

シュっと対応

トランザクションがコミットされる前に Resque 経由で Mailer が動いてしまうことが問題なので Resque に積むタイミングをトランザクションがコミットされた後にすれば解決します。(この例の場合なら do_something2 の位置をずらせばほぼ解決ですが)

1
2
3
4
5
6
7
8
9
10
11
12
class Hoge
def exec
ActiveRecord::Base.transaction do
do_something1
do_something2
end

send_email(model.id)
end
end

Hoge.new.exec

めでたしめでたし……?

ダメじゃん

これではダメです。 次のように ActiveRecord::Base.transaction がネストしているケースで問題が発生します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Hoge
def exec
ActiveRecord::Base.transaction do
do_something1
do_something2
end

send_email(model.id)
end
end

class Fuga
def exec
ActiveRecord::Base.transaction do
do_fuga1
Hoge.new.exec
do_fuga2
end
end
end

Fuga.new.exec

実際のDBのトランザクションは Fuga 側のブロックの終わりにコミットされるため、トランザクションの外に追いやったはずの send_email がトランザクションの中残ったままになってしまっています。

after_commit が使えれば良いのですが、 after_commit は ActiveRecord のコールバックなので Model 以外では使えません。 Perl を書いていたときに使った DBIx::TransactionManager::EndHook を思い出し、それっぽいのものがないのかを探しました。

after_commit_everywhere

この記事を見つけ、そのコメント中で宣伝されていた after_commit_everywhere という Gem がインタフェース的にまさに欲しかったものでした。 中身を読んでみたところかなりコンパクトで、いざとなったらまるまるメンテできそうで安心したので採用しました。

after_commit_everywhere を使用して書き直すと以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Hoge
include AfterCommitEverywhere

def exec
ActiveRecord::Base.transaction do
do_something1

after_commit do
send_email(model.id)
end

do_something2
end
end
end

class Fuga
def exec
ActiveRecord::Base.transaction do
do_fuga1
Hoge.new.exec
do_fuga2
end
end
end

Fuga.new.exec

これで Hoge が意図せずトランザクションの中で実行されたとしても send_email はコミットされた後に実行され、 Mailer が処理を行う時点で最新の Model を取得できるようになりました。

終わりに

多くのケースでは ActiveRecord のコールバックを普通に使えば十分ですが、たまに ActiveRecord ではない部分でもコミットをトリガーとして処理を実行したくなるかと思います。 使いすぎると可読性がヤバいことになりそうなのでご利用は計画的に。


明日17日はyo_wakaによる新作発表らしいです。お楽しみに。

ブログをConoHaからS3に移動しました

ホストの引っ越しついでにDark Advent Calendar 2017の23日目の記事です。 余裕の遅刻です。

概要

ConoHa VPSからS3+CloudFrontに引っ越しました。

発端というか愚痴

ConoHaの運営から以下のメールが来ました(一部抜粋)。
Twitterを検索すると、似たようなメールが来て止められている事案がちらほらあるようです。

1
2
3
4
5
6
7
8
9
10
上記IPアドレスにてご利用のVPSにつきまして、CPUの使用率が
高い状況が継続しております。

一時的なものであれば問題ございませんが、継続する場合、
収容ホストへの負荷影響や、他のお客様への影響が懸念されます。

そのため、大変恐縮ではございますが、該当VPSのシャットダウンを
実施させていただきました。

なお、ご運用状況の見直しもご検討くださいますと幸いです。

半年くらい前から1GBと2GBの2つのプランのVPSでマイニングをしていました。 CPU使用率がほぼ0%だとこちらが損だったので出来る限り使っておきたかった、かつ変なコインが欲しかったのもあり、採算度外視で掘り始めました。
2GBの方は blog.mihyaeru.com を運用していたサーバーです。 1GBの方は、もうちょっと掘りたくなったので2GBの方で掘り始めて数日経ったくらいの頃に追加して、マイニング専用としていました。

止める前に警告を出してから止めるならわかるのですが、いきなり止めた後に事後報告をしてくるという姿勢と、こちらは100%使わないと損なのに100%使ってはいけないという運営の方針が嫌だったので、言われた通り「運用状況の見直し」として全て解約して別の場所に乗り換えることを即座に決めました。

AWSをいじる練習として、いずれS3に乗り換えるつもりだったので良い機会になりました。
これでお互い幸せなんだと思います。

引っ越し

やりたかったのは、S3 + CloudFront + 独自ドメイン + HTTPSという構図です。
詳しい手順については、それぞれリンクした記事などを参照すれば良いので書きません。

第一段階: 新規WebサイトでS3 + 独自ドメイン + HTTPS

参考: https://qiita.com/Ichiro_Tsuji/items/c174d580587a622d3358#fnref1

wwwsample. というサブドメインで作っていました。
問題なく順調に終わったので特に書くことは無いです。

第二弾階: 新規サイトでS3 + CloudFront + 独自ドメイン + HTTPS

参考: https://qiita.com/74th/items/62aaf34c080e747ba420

ドメインの認証に使うためのメールアドレスの用意に手こずりました。 MXレコードを設定し忘れたため、メールを受信できていないというオチでした。 実はメールで認証する必要はなく、DNSレコードをいじることで認証することができました。 参考にした記事が1年以上前のものだったので、新しい方式が追加されたことがわからない感じでした。

もう1点ハマったのが、「US Eastリージョンの証明書でないとCloudFrontで使用できない」という点です。
明らかに証明書を作成できているのに、それをCloudFront側から参照できなくて???となっていました。
最終的に https://stackoverflow.com/questions/44230614/aws-cloudfront-custom-ssl-certificate-disabled にたどり着いてこの事実を知りました。

第三弾階: ブログをS3 + CloudFront + 独自ドメイン + HTTPSに移動させる

お試しサイトを動かしたことでやり方は全て理解したので、ほとんどはさくさくーっとできました。
いくつかハマったのでメモっておきます。

なぜか blog.mihyaeru.com にアクセスすると、S3ぽいURLにリダイレクトされてしまうという問題が発生して謎でした。
アクセスログを見たらstatusが307になっていたので、「s3 cloudfront 307」とかでググったら http://miyasakura.hatenablog.com/entry/2016/12/28/200000 が見つかり、Invalidateして事なきを得ました。

その後もう1つ、 /archives/ のような root 以外のディレクトリにアクセスした際に /archives/index.html が表示されるのではなく403だか404ぽくなってしまう問題が発生しました。
これもテキトーにググッた結果 https://qiita.com/naoiwata/items/3c6626cbeacbb44d4aa8 が見つかり、CloudFrontでS3のバケットを直接originに設定せずに、WebホスティングしているURLをoriginに設定することで、想定通りの動きになってくれました。

Hexoのデプロイ

hexo-deployer-s3hexo-deployer-s3-cloudfrontがあり、CloudFrontを噛ませている場合はInvalidateを実行するために後者の方を使うのが楽そうな感じでした。
が、地味にhexo-deployer-s3からフォークした後に差が開いてしまっているようで、「なんで本家にオプション機能としてマージしなかったんだー」感が強くなってしまい、hexo-deployer-s3を使いつつInvalidateはaws-cliでやることにしました。どっちみち make deploy でラップしているので手間は変わらないかなーという感じです。

終わりに

数時間でできると思っていたらハマりまくりで、けっこう時間を使ってしまいました。 その代わりS3, CloudFront, Route 53, ACM, SNS, SESあたりをざっくりいじったりドキュメントを読んだりできて良い経験になりました。
参考にした記事だけだと基本的な情報が不足していたので、いじった周辺の公式も後から読みました。 やはり基本から順を追って説明してくれる公式のドキュメントはありがたいなと感じました。 ドキュメントがしっかりしていると入門者的にとてもありがたいです。

マイニングは、とりあえず家で余っているPCたちで細々とやっていきます。
年明けたら仮想通貨の取引で儲けた分でマイニング用のマシンを組もうかなと考えています。

それでは良いお年を(?)。

転職してから1ヶ月経ったらしい

実は転職初日に書こうと思っていたのに気づいたら1ヶ月経っていた😇
一応、ネット上では明示的には所属組織を明らかにしていないマンなので、その辺りはふわっとさせておく。

転職の動機

一言でまとめると、いわゆる音楽性の違いというやつ。
もちろん下記以外にも他にもいろいろある。

経営の意思決定内容に一社員として納得感が持てないことが多くなってきたことによる、経営方針へのミスマッチ。詳しい話はNDA的によくなさそうなので割愛。

個人的にソシャゲのガチャが好きではなかったのに、それを提供する側になっていたことによる、事業内容のミスマッチ。他と比較するとガチャの厳しさはゆるかったが、それでも違和感を感じてしまっていた。

個人的にどうありたいかという方針と会社の方針がずれることは仕方のないことだと思う。無理に合わせたりするのではなく、その時々で方針がマッチするところに所属するのが幸せそうだ。

転職先はどう選んだか

人づてだったり転職サイトとかで興味のある会社へ話を聞きに行った。話を聞きに行った場合は中のエンジニアの方と話すスタイルだった。

急いで今すぐに転職したい感じではなかったので、中の人と話してみて自分の中の条件と合う会社があれば、1社ずつ順番に受けていこう、ダメだったらまた探す所から始めよう、という感覚で転職活動を行っていた。新卒の時の、並行して何社も受けて、いろんな会社で面接をして、最終的に決めた会社以外は辞退して、、、みたいな構図が個人的にはかなり心理的な負担だったため、そいう方針にした。

会社を選ぶときの条件というか基準はこんな感じだった。
ミッションへの共感は一番強く、他はだいたい順不同。

  • 会社のミッションに確かな価値を感じ、を自分もそれ実現したいと思えるか
  • 技術的に広い範囲を触ることができるか
  • オープンな社風か
  • 働き方に自由があるか
  • 確率によらない価値を提供する事業を持っているか
  • 強い人が多いか
  • (家から近いか)
  • (他にもいろいろあった気がする)

話を聞きに行くこと5社目くらいで、今の会社にたどり着いた。
最初に話を聞きに行った後のタイミングで「ここだな」と確信した記憶がある。
自分でもかなりマッチしていると確信していたので、これは通るという謎の自信があった。
無事選考1社目で内定をいただき、初めての転職活動を終わらせた。

実際に転職してみて

外から見て感じていたイメージや、面談面接時に聞いたイメージ通りの雰囲気だったので安心した。社内の価値基準が社員に浸透しているのが日常から受け取れる。
イメージ以上だったのは、全体的なテンションの高さ。

働く時間は明らかに増えた。前職が業界内では残業がかなり少ない部類だったので想定通り。早くコードベースに慣れるために時間をかけてる感じがする。
ハードめに働けるのは個人的には20代のうちくらいかな、という感覚があるので頑張っていきたい。

夕飯を会社負担で食べられるのが地味に便利。好きなカレー屋さんのカレーを会社で注文できてしまい、完全に太る気配が忍び寄ってきている。

Web系の会社らしく、GitHubにSlackにMackerelにKibanaにみたいな感じで使用するツール等が前職とあまり変わらず、ツール的な意味で馴染むのは簡単だった。
コミュ力が足りないので人的な意味で馴染むのは数カ月掛かりそうだ。

最後てきとうになったけど、あとは、やっていきの気持ちだ。

ニート日報 2016-10-02

ニート最終日

最終日も特に特別なこと無く終わり。
マイクラをやっていた時間が多くて、この先心配になってしまう。

dotfilesのセットアップをmakeに移行する作業をひとまず終わらせた。
もう少しやりたかったけどマイクラに時間を吸い取られてダメだった。
強い自制心が必要だ。

ブログじゃないサイトのトップページもデザインなしのやつを作ろうと思っていたけど、これもマイクラに時間を(ry

最終日になって、もっともニートっぽい1日を送った気がした。

全体を振り返って

自制心を保つために設定したTODOだったが、とくに技術系の「やっておくと何かの役に立つけど緊急ではないもの」に手を出すモチベーションがなかなか上がらなかった。
残ったものは、働きながらの日常でこなしていくことになるだろう。
残したと言いつつ、前からやりたかったことはチマチマで進められたからある程度は満足している。

とくに後半は休養という名目でダラダラしていたのが目立った。
しかしそのおかげで、退職直前から続いた体調不良も治すことができた。
が、体調のために関西旅行を犠牲にしたのは痛かった。
数年以内に大きな休みを作って行くぞ。

23連休という膨大なお休みだったけど予想通り終わってみればあっという間だった。
またいずれ、落ち着いたタイミングで長期休暇が取れたら嬉しい。
(退職じゃなくて普通にまとまった大きな休みが取れたらいいなーという希望)

というわけでたくさん休んだことだし、明日からお仕事頑張るぞい!

TODO進捗

https://gist.github.com/mihyaeru21/7ec2e6b408d0c7f546274fd4b5a1e610

  • dotfilesのセットアップ移行完了

ニート日報 2016-10-01

ニート22日目

ニート生活残り2日。
前日から急に生活のリズムが崩れて睡眠時間帯が6時間くらいずれてしまった。

あとちょっとで終わるところだった本を終わらせた。
人工無能の本はちょっと古いけど、それなりにRubyの練習にもなった。

dotfilesを整理していたらMinecraftを始めることになってしまった(?)。

天一の日

天一botが今回限りで活動終了なのが悲しかった。
↓が天一に行ってきた様子。

Minecraft

なんと残すところ1日ちょいの段階でマイクラを始めてしまった。
閉じた?鯖でまったりやってる。
初めてだからいろいろと新鮮で面白い。
これは時間を吸い取られてしまうのもわかる。

TODO進捗

https://gist.github.com/mihyaeru21/7ec2e6b408d0c7f546274fd4b5a1e610

  • 恋するプログラム終わり
  • dotfilesの整理

ニート日報 2016-09-30

ニート21日目

ニート生活残り3日。
医者へ行ったのとキャズムを読んだだけ。
まさかのタイミングで不眠になってしまった気がする。

キャズムの感想はこっちに書いた。
家よりも喫茶店で本を読むと捗ることに気づいた。
読み進めるのにエネルギーが必要な本は喫茶店で読むようにしてみよう。

TODO進捗

https://gist.github.com/mihyaeru21/7ec2e6b408d0c7f546274fd4b5a1e610

  • キャズムを撃破

「キャズム2」を読んだ感想

入社までに読んでおくべき本その2のキャズム。
なんとか読み切ったので若干雑だけど感想とかまとめ。

本の大雑把な内容

(主に)いわゆるハイテク系の事業をスケールさせるための「マーケティング」に関する知識体系をまとめた本。
ハイテク系かつ主にB2B向けのモデルっぽい。

キャズムとは、アーリーアダプターとアーリーマジョリティの間に存在している溝のこと。
この溝を乗り越えるためのマーケティングの話がメイン。
一般的に想像される特定部署のみが動くマーケティングではなく、企業の全部署が一丸となって行う活動と捉えておくのが安全。

マーケティング手法は、製品のテクノロジーライフサイクルごとに適切なアプローチを選択する必要がある。
どのグループが何に価値を感じるかは次の箇条書きの通り。

  • イノベーターには、テクノロジーに
  • アーリーアダプターには、製品に
  • アーリーマジョリティには、市場に
  • レイトマジョリティには、企業に

キャズムを乗り越えるための戦略の立て方をかなり詳細に、かつ具体的な例を伴って紹介している。
それぞれに実際の事例も紹介している。
ホールプロダクトの概念がとても重要。

感想的なやつ

「あなたのチームは、機能してますか?」と比べると若干の読み難さを感じた。
あっちが異常に読みやすすぎた感じだ。

戦略は、本で事例だけ見るとそんなに大変そうには見えないけど現実は異常に大変なんだろうなと感じた。
多くの経営者はキャズムを知識として知っているが実践するのは非常に難しいと本の中でも触れられていた。

この本を読むまで、アーリーアダプターとアーリーマジョリティはほとんど似たような印象を持っていたが、実際には全く違う価値観を持ったグループだった。
アプローチの仕方も全くと言っていいほど違って困惑するレベル。
これは強く意識しないでいると自然にキャズムにハマってしまうのは当然な感じだ。

マーケティング主導で機能開発するフェーズも必要だという観点を与えられたのが貴重だった。
あー、でもよく考えたら当たり前のことだ。
自分の中でのマーケティングの定義が「製品の中身には関与せず広告とかを手がける人」という感じで狭く偏っていただけだった。

この本でも「あなたのチームは、機能してますか?」でも、(新興企業では)特定の部署が独立して動くことよりも、全社で1つの目標に向かって全部書が共闘することの重要性が語られていた。
重要なのは個人の成功、部署の成功ではなく会社全体の成功だということを常に頭に入れておかねば。
それと、開発以外の広い視野も。

ニート日報 2016-09-29 LINE DEVELOPER DAY 2016

ニート20日目

ニート生活残り4日。
夕方までLINE DEVELOPER DAY 2016だった。
必読の本の2冊目を読み始めた。
前日のついったTLの影響で、久しぶりに蒲田のらーめん 潤へ行った。

LINE DEVELOPER DAY 2016

去年も参加したLINEの開発者向けイベント。
参加無料にも関わらず、内容はとても充実してるわ、開場が綺麗だわ、おみやげがすごいわで、とにかくLINEすごいって感じだった。

参加者用のLINE Botが新機能のデモンストレーションをしつつ、便利に情報を提供してくれたのが良かった。

夕方、疲れてしまったため帰宅ラッシュが始まる前に帰った。
以下、気になったセッションの感想をちょこっと。

LINEが乗り越えてきた困難な問題

LINEにて過去に起きた障害の話。
まさに障害報告という感じだった。

普段は1日に10件くらいしかない重いAPIが全ユーザから同時に叩かれるとは……とんでもないインパクトだった。
障害が起きてから改めてサービスの構成を俯瞰すると、たしかに問題になりそうな気配はありそう。
定期的に現状のアーキテクチャに疑問を保つ必要があるんだなーという感想を抱いた。

Security x LINE Platform

LINEの暗号化とかの話。

標準のTLSじゃなくて改造?したものを使っていたとは知らなかった。
通信の暗号化だけではなく、そこに載せるメッセージ自体も暗号化していたようだ。
ECDHで会話相手(グループも)と鍵を共有しているっぽい。
これによって、運営ですらメッセージの内容を覗き見ることができないようになったのでよりプライベートな会話()が楽しめるようになった気がする。

後半に言っていた、端末のHTTPS通信に自分で中間者攻撃を仕掛けて通信内容をアレするやつ、まじかーって感じだった……。
セキュリティ系は本当に必要な知識が多くて辛い。
この件については、SSL Pinningしましょうという話だ。

LINEに感謝している様子です

昼飯代としてヒカリエのギフト券2000円分が参加者に配られた。
それを使い、三浦三崎港 恵みにてほぼ2000円でランチをいただいた。

参加アンケートに答えると貰えたお土産。
タンブラー、スマホとかタブレットを立てるやつ、ビーコンが貰えた。
LINEにビーコンの機能が追加されたので、その機能を遊んでもらうために配るという太っ腹な戦略。
ありがとうございます!

TODO進捗

https://gist.github.com/mihyaeru21/7ec2e6b408d0c7f546274fd4b5a1e610

  • キャズムを50ページくらい読んだ

ニート日報 2016-09-28

ニート19日目

ニート生活も残すところあと5日。
信じられない。
お昼に新宿で某氏と飯って新宿で映画を見る作戦を決行。

新宿マン

お昼は鳥料理が美味いお店でチキン南蛮定食を食べた。
野菜の種類が多かったし、鶏肉が柔らかくて美味かった。
若干ご飯が多かったから、また行くとしたらご飯少なめで頼もう。

お昼後、ついに君の名は。を見る決意をしてTOHOシネマズ新宿へ。
14時20分の上映で見れると思ったら14時20分の時点でまさかの満席だった。
16時55分の回のチケットを買ってルノアールへ避難。

ルノアールにて「あなたのチームは、機能してますか?」を半分くらい読んだ。
この本は家に帰ってからも読んで読み終わった。
感想とかはこっちに書いた。

君の名は。の感想

絵が綺麗だった。
とくに星の描写が好きだった。
あと新海誠映画の定番?である、歌の内容とストーリーのコラボが良い具合だったように感じた。

ストーリーについては、中盤から予想した終わりにだいたい向かっていったのが、見ていて心地よかった。
大体予想通りではあったけども、ちょいちょい予想とタイミングをずらしてくる感じも良かった。

ネタバレせずに感想を書くと小並感になることがわかった。

TODO進捗

https://gist.github.com/mihyaeru21/7ec2e6b408d0c7f546274fd4b5a1e610

  • 本を1冊読んだ