Codaybook

サーバサイドエンジニアが必死に作成した!発見した!を綴るブログ



Jenkinsから対話式のシェルを実行

Jenkinsからあるサーバに置いてあるシェルスクリプトを実行しなくてはいけないことになりました。 実行するだけならジョブのシェル実行にssh $HOSTNAME $SHELL_PATHを記述すれば良いですが、 実行しなくてはいけないシェルは対話式になっていました(◞‸◟)
ということで、対話式のシェルを実行するためのシェルを作成してJenkinsからでも実行できるようにしました。

#!/bin/bash

SHELL_PATH="/usr/local/bin/deploy.sh"
TARGET_ENV="develop"
TARGET_BRANCH="master"

expect -c "
set timeout -1
spawn  $SHELL_PATH
expect -re \"Select Environment?.*\"
send   \"${TARGET_ENV}\n\"
expect -re \"Select Branch?.*\"
send   \"${TARGET_BRANCH}\n\"
expect eof
exit
"

対話式に対応させるためにexpectコマンドを使用して実現させました。細かく説明しますと、
expect -c "[コマンド群]"スクリプトを実行する前に、実行するコマンドを指示する。コマンドはシェルに壊されないようにクオートで囲むべきとされている。
set timeout -1タイムアウトにする時間を設定できる。無制限にしたい場合は-1を設定する
spawn [実行コマンド]:ここで実行するシェルを指定する。
expect -re "[対話の対象となる文字文字列]":対話の対象になる文字列を指定する。
send "[対象の応答]":対話に対する応答の文字列を指定する。
expect eof,exit:cronやjenkinsから実行する場合はexpect eofexitとする必要がある。

このシェルを使用すると対話式のシェルでもJenkinsから実行できるようになります。うむ、超絶便利!

Ruby on RailsにてRedisにマスタデータのModelをキャッシュ

とあるシュミレータをruby on rails上で作成することになり、ある処理を何万回、 何百万回と動作させなければいけなくなった。例えば以下の処理が本番環境で動作している。

def cards
  (1..1000).each do |index|
    index.to_s + ": " + Card.all[Random.rand(Card.all.size)].name
  end
end

1000回ほど、カードというマスタデータのnameカラムをランダムに1件ずつ取得している処理だが、

Completed 200 OK in 17243ms (Views: 29.3ms | ActiveRecord: 2451.8ms)

ぐらいの処理時間になってしまう。特にActiveRecord: 2451.8msは1回の処理でmysqlに アクセスしてしまうためにモデルデータをなんとかキャッシュできないかと考えなければいけない....!
というわけでruby on railsredisを導入し、モデルデータをキャッシュしてしまおうと対応にでた。

def cards
  (1..1000).each do |index|
    cache = Rails.cache.fetch("card_data", expires_in: 1.hour) do
      Card.all.to_a
    end
    index.to_s + ": " + cache[Random.rand(cache.size)].name
  end
end

card_dataというkeyのvalueにCardモデルの内容を全てキャッシュするように記述してみました。 (expires_inに関してはTTL時間で1時間だけキャッシングするという記述)

これで処理してみると

Completed 200 OK in 16713ms (Views: 94.6ms | ActiveRecord: 0.4ms)

という結果を得ることができました。なんとActiveRecord: 0.4msという速度になり、logを確認すると mysqlログもなくなりキャッシュからデータを取得できていることも確認できました。 (Views: 94.6msになってるのはなぜ・・)

ちなみに実際、どのようにデータがキャッシュされているかは以下コマンドで確認することができます。

$ redis-cli                   // redisコンソールの起動
127.0.0.1:6379> keys *        // キャッシュされているkey一覧
1) "card_data"
127.0.0.1:6379> get card_data // valueの取得

コマンドは大変!クライアントソフトないの!?っという人もいると思います。(自分のことです...) そういう方はRedis Desktop Managerを使用してみてはいかがでしょうか。 以下のような感じでredisを確認することができます。これは便利!

f:id:nisei275:20160809115244p:plain

Modelファイルにスキーマ情報を簡単記述「annotate」

業務でruby on railsに触れて半年目。いろいろな便利なgemに触れてきました。 ということで今回、あったら便利だなぁというgemを紹介いたします。
今回紹介するgemはannotateです。

github.com

導入の仕方はGemfileに以下1文を記述して$ bundle installいます。

gem "annotate"

annotateをインストールした後に以下コマンドを入力します。

$ bundle exec annotate

そうすると、Annotated (1): Playerみたいな文言がmodelの分出力され、 app/models/以下にあるmodelのファイルにスキーマ情報が以下のようにコメントとして追記されます。

# == Schema Information
#
# Table name: cards
#
#  id                :integer          not null, primary key
#  character_id      :integer          not null
#  name              :string(255)      not null

いちいちテーブルの情報を見なくても、このmodelにはこういうカラムが存在しているんだなぁというのが 一目瞭然になります。非常に便利なgemですので是非入れてみてください。

crystal-langのファイルをAtomで開く準備

最近、crystal-langに触れています。rubyのように書けて実行速度が爆速なのはありがたいですね。
さて、crystal-langAtomエディタで主にプログラミングしているのですが、カラーシンタックスPlain Textを選ばれてわざわざrubyに変更するのが面倒くさいと思いました。crという拡張子rubyのカラーシンタックスになるように以下パッケージを導入しました。

github.com

設定はメニューバーから[Atom]->[Open Your Config]を選択して以下のように追記をします。

"*":
  "file-types":
    cr: "source.ruby"
    tx: "text.html.basic"

この設定により、crrubyのカラーシンタックスになります。(ついでににtxhtmlに設定しています。)
Atomはバージョン1.5.3に書いた記事です。

Unity5.3にしたときのシーン切り替えで暗くなる

Unity5.3がリリースしてすんなり動くかと思った第2弾。今度はSceneManager.LoadSceneでシーン切り替えを実施した際に、急に画面が暗くなります。 それを解決するためには、以下手順を踏んで設定を変更する。

  1. メニューバーからWindow=>Lightingを選択し、Lightmapsを3つのタブから選択する。
  2. Autoのチェックを外して、Buildをクリックする。

この手順を踏むとSceneManager.LoadSceneした際に画面が暗くなりません。情報を提供していただいたクライアントエンジニアさんに感謝。

Unity5.3にしたときのシーンの切り替えで警告文

12月上旬にUnity5.3がリリースされました。新しい2DツールJSONの公式サポート、カスタムコルーチン等、魅力的な機能が 多く追加されたのですぐにアップデートしました。5.2から5.3のアップデートなのですんなり動くだろう(根拠なし)と思っていましたが、 以下エラーが発生しました。

"UnityEngine.Application.LoadLevel(int)' is obsolete: `Use SceneManager.LoadScene'".

シーンファイルの切り替えはApplication.LoadLevel([シーンナンバー])で実施していましたが、なんとこれはもう時代遅れだ!SceneManager.LoadSceneを使えや!というUnityの警告が出力されました。ということで以下のように書き換え。

using UnityEngine.SceneManager;
// Application.LoadLevel([シーンIDまたはシーン名]);
SceneManager.LoadScene([シーンIDまたはシーン名]);

これでUnityに怒られなくなります。

今何かと話題のCrystalを入れてみる

高い生産性を兼ね備えているOSなプログラミング言語Rubyですが、そのエレガントな文法をそのままに C言語に近いスピードで動作するコンパイル言語CrystalHello Worldしてみました。ちなみにOSOSX10.11.2で本記事の内容を実施しています。

まずは、OSX用パッケージマネージャーのHomebrewをインストールします。以下のサイトでインストール方法が記述されています。
<<Homebrew>>

$ brew update
$ brew install crystal-lang

これでもうCrystal言語導入完了です。ちなみに自分はインストールする際に、エラーが発生したしまいましたが、 だいたいはccコマンドが足りない等のエラーです。エラーの内容をよく確認し不足しているものを導入してください。

さて、プログラミングです。その前に以下コマンドを実行します。

$ crystal init

これでなんと初期プロジェクトファイル(プログラミングして際に必要なGITやディレクト等)を作成してくれます。 これを実施してからプログラミングしましょう。

試しに簡単な引数を与えてその値を2倍するプログラムを書いてみました。

そして、ビルドして実行してみます。

$ crystal build src/Testc.cr
$ ./Testc 4
8

驚くほどRubyの文法でビルドして実行できました。コンパイル速度はかかるもの、C言語に引けを取らないほどの実行速度を誇ります。
Crystalは、ライブラリ経由でC言語の関数を呼び出しやすいように設計されており、 目指すところはC言語の代替物という位置付けになりそうです。 自分の目指すところは、Unityで速度を出したいところはCrystalでという使い方ができないか模索中です。