DelayedJobのバックグランド処理でサーバーが落ちた時にすること

2017年08月25日
区分
Rails
報告者:
endo

こんにちは、endoです。

今回はDelayedJob先生のバックグラウンドの処理が重くて、スワップが発生してサーバーがお亡くなりになりました。

対処として、サーバー再起動を行いました。

この時、サーバー再起動で処理は繰り返されないだろうと勘違いしていました。

弊社ではDelayedJobの設定でリトライをしないようにしております。

詳細はDelayed::Job で絶対にやっておいた方がいいたった1つの設定 をご確認ください。

視界、夜中に再度実行されてまた、サーバーがお亡くなりになりました・・・

  1. サーバー再起動
  2. 8時間後にもう一度再実行←こいつの正体が意味わからない

設定を確認しました。

config/initializers/delayed_job_config.rb

Delayed::Worker.max_run_time = 8.hours ←こいつ

DBに書き込みをしていないので、DelayedJobが生きていると判断してくれて、再度実行するように気を利かせてくれました。

なので、DelayedJobで落ちるようなことがあったら、確実に失敗させましょう。

Delayed::Job.find(x).fail!←IDは適当に書き換えてください。

以上です。

HABTMのテーブル作成方法

2017年06月19日
区分
ruby
報告者:
endo

こんにちは、endoです。

今回は「HABTM」のテーブル作成の方法です。

「has_and__belongs_to_many」の多対多の関係性を頭文字で略語で表示しているものです。

発音はなんて発音されているのでしょうか。 自分は「ハブトゥム」って読んでいますが、どんな呼び方をしているのか気になります。 こんな呼び方があるよって方は、ぜひ教えてください!

さて、「HABTM」ですが、テーブル作成で便利に作成することができます。

rails g migration create_join_table_facility_prefecture facility prefecture

こんなファイルが出来上がります。

class CreateJoinTableFacilityPrefecture < ActiveRecord::Migration
  def change
    create_join_table :facilities, :prefectures do |t|
      # t.index [:facility_id, :prefecture_id]
      # t.index [:prefecture_id, :facility_id]
    end
  end
end

これでもいいのですが、foreign_keyに対して爪が甘いなと思います。

そこで、これを改造します。

class CreateJoinTableFacilityPrefecture < ActiveRecord::Migration
  def change
    create_join_table :facilities, :prefectures do |t|
      t.references :facility, index: true, foreign_key: true
      t.references :prefecture, index: true, foreign_key: true
      # t.index [:facility_id, :prefecture_id]
      # t.index [:prefecture_id, :facility_id]
    end
  end
end

なお、改造しなくてもrails5.1.1は下記のコマンドでいけます。

rails g migration create_join_table_facility_prefecture facility:references prefecture:references
class CreateJoinTableFacilityPrefecture < ActiveRecord::Migration[5.1]
  def change
    create_join_table :facilities, :prefectures do |t|
      t.references :facility, foreign_key: true
      t.references :prefecture, foreign_key: true
    end
  end
end

issue自体は下記で上がっていました。

create_join_table should include indexes and foreign key contraints

取り込まれて使用できるようになっております。

foreign_key好きが突っ込むよな!って思ったので、嬉しかったです。

アクトインディではHABTMについて語りたいエンジニアを募集しております。

timecopのちょっとした使い方

2016年12月19日
区分
advent-calender
報告者:
endo

この記事はアクトインディ Advent Calendar 2016 19日目になります。 どうぞよろしくお願いします。

今回はtimecopについて説明します。

timecopとは

timecopはRubyのgemです。

過去の時間、未来の時間の日付で動作するようになります。

なお、現実では戻れないので、そこは注意が必要です。

簡単な使い方

簡単な使い方です。

Timecop.travel(2017, 1, 1) do
  Time.new
end
=> 2017-01-01 09:00:00 +0900

メソッドのブロック内の時間が未来になっているかと思います。

これを利用して、テストでは過去の時間、未来の時間にすることで特定のタイミングでのテストが書けることができます。

ちょっとした使い方

用途としては、テストで使うのが一般的だと思います。

ただ、特定のタイミングでのバッチ処理の結果が欲しい場合があります。

その中身のメソッド内で下記のようなコードがあったとします。


class Batch

  def self.update_analyses
    end_on = Date.today
    start_on = end_on - 3
    ...
    ...

  end

end


こういうメソッドの過去のデータが消えていて、過去のデータが欲しい場合にtimecopが役立ちます。

Timecop.travel(2016, 4, 1) do
  Batch.update_analyses
end

過去のデータが取れます。

以上です。

本当に時間が戻れればいいんですけどね。

vim on tmux

2016年12月06日
区分
advent-calender
報告者:
endo

この記事はアクトインディ Advent Calendar 2016 6日目になります。 どうぞよろしくお願いします。

今回は私の開発環境の画面の使い方について説明します。

細かい開発環境の設定は割愛します。

最近は1画面でどのように操作するかを考え、画面の使い方を変更しました。

変更結果の紹介になります。

開発環境

前提条件の開発環境です。

  • editor
    • vim
  • terminal
    • iterm2
    • tmux

画面の使い方

開発環境の画面の使い方

上部画面をeditorにして、下部をターミナル作業にしています。

以前はeditorがメインの画面だったのですが、ターミナルのコンソールで値の確認や実行結果を見たいときがあります。

そんな時に下に画面を置いておけば、すぐに移動できます。

感想

作業環境を徐々に自分の使いやすい風に構築していくことが重要だ。

今後もより良い開発環境を構築できるようにしていきます。

ES2015の新記法

2016年12月03日
区分
advent-calender
報告者:
endo

この記事はアクトインディ Advent Calendar 2016 3日目になります。 どうぞよろしくお願いします。

ES2015の新記法について、まとめました。

ES2015の新記法

変数の宣言

let

  • 変数の重複を許可しない
  • ブロックスコープ({})を認識する
var x = "foo";

var x = "bar";

let y = "foo";

let y = "bar";
if (true) {
  var i = 5;
}

console.log(i);

if (true) {
  let x = 5;
}

console.log(x);

定数(const)

const TAX = 1.08;
let price = 100 * TAX;

データ型

分類 データ型 概要  
基本型 数値型(number)    
基本型 文字列型(string) シングル/ダブルクォートで囲まれた0個以上の文字の集合  
基本型 真偽型(boolean) true(真)/false(偽)  
基本型 シンボル型(symbol) シンボルを表す(ES2015の新記法)  
基本型 特殊型(null/undefined) 値が空、未定義であることを表す  
参照型 配列(array) データの集合(各要素にはインデックス番号でアクセス可能)  
参照型 オブジェクト(object) データの集合(各要素には名前でアクセス可能)  
参照型 関数 一連の処理(手続き)の集合 ### String型の不思議
let x = new String("foo");
let y = "foo";

x == y
=>true

let z = new String("foo");
x == z
=>false

x, zが一致しないのはnew Stringで生成したものは、objectになります。

参照型になっているからこの現象が起きます。

typeof(x);
=>"object"

x,yが比較して一致するのは、文字列リテラルを比較する場合は、一時的にString型にしているからです。

文字列リテラルを持つ値は、String オブジェクトのあらゆるメソッドを呼び出すことができます。JavaScript は自動的に文字列リテラルを一時的な String オブジェクトに変換し、メソッドを呼び出して、その後一時的に作られた String オブジェクトを破棄します。String.length プロパティを文字列リテラルで用いることもできます :

文法とデータ型

シンボル

  • Rubyのシンボルと違い、symbolで生成されたものはユニーク扱いになる
let x = Symbol('sym');
let y = Symbol('sym');

typeof(x);
=>symbol
x.toString();
=>Symbol(x)
x == y
=>false

Mapオブジェクト

  • 連想配列を管理するためのオブジェクト(今まではオブジェクトリテラルで管理)
  • データの検索が早い

伝統的な書き方

var x = { 'apple': 'りんご',
          'orange': 'みかん',
          'strawberry': 'いちご' }
console.time('associative_array');
x.apple
console.timeEnd('associative_array');

map

var x = new Map([['apple', 'りんご'],
                 ['orange', 'みかん'],
                 ['strawberry', 'いちご']]);
x.set('banana', 'バナナ')

console.time('map');
x.get('apple');
console.timeEnd('map');
x.keys();
x.size

オブジェクトリテラルとの違い

  1. 任意の型でキーを設定できる
    • オブジェクト/NaNでもキーになりうる
  2. マップのサイズを取得できる
    • sizeメソッドで要素数を取得できる
  3. クリーンなマップを作成できる
    • オブジェクトリテラルは、Objectそのもの 配下にはObjectが標準で用意しているプロパティが最初から存在している

キーに関わる3つの注意点

  1. キーは「===」演算子で比較される
  2. 特別なNaNは特別ではない
var x = new Map();
x.set(NaN, 'foo');
x.get(NaN);
  1. オブジェクトの比較には注意
var x = new Map();
x.set({}, "foo");
x.get({});

Setオブジェクト

  • 重複しない値の集合を操作する(初めての概念自体)
let i = new Set([1, 5, 100, 10, 5]);
for (var int of i.values()) {
    console.log(int);
}
  • オブジェクトの比較はMapと同じ

書き方

代入

分割代入

  • 端数は切り捨てられる
  • オブジェクトの場合は、変数の並び順は考慮しなくても大丈夫

配列

let [x, y, z] = [1, 2];

連想配列(オブジェクト)

let associative_array = { x: 1,y: 2, z: 3 }
let { x, z, y } = associative_array;

関数

アロー関数

  • 関数リテラルのfunctionを記入しなくて良い
  • 1行で書く場合は、returnを書く必要がない

関数リテラル

let getSquare = function(num) {
    return num * num;
}

アロー関数

let getSquare = (num) => {
    retun num * num;
}

let getSquare = (num) => num * num;

変数展開

テンプレート文字列

let name = "Tom";
let greet = `Hello ${name}`;

引数

引数のデフォルト値

  • 今までは引数にデフォルト値を渡すことはできなかった
function getSquare(num = 2) {
    return num * num;
}

let getSquare = (num = 2) => num * num;

getSquare(5);

名前付き引数

  • {}を使用することで名前付き引数になる
  • 使用する場合に{}で指定する
let getSquare = ({num = 2}) => num * num;

getSquare({num: 5});

let getSquare = ({num}) => num * num;

getSquare({num: 5});

可変長引数の定義

  • ...(スプレッド演算子)で可変長引数になる
function sum(...nums) {
  let result = 0;
  for (let num of nums) {
      result += num;
  }
  return result;
}

「…」演算子による引数の展開

  • 「…」演算子は、実引数で利用することで、配列(正確にはfor..ofブロックで処理できる)をここの値に展開する
Math.max(1, 3, 5, 4);
let x = [1, 3, 5, 4]
Math.max(x);
=> NaN
Math.max(...x);
=> 5

引数の戻り値

複数の戻り値を個別の変数に代入する

function getMaxMin(...nums) {
    return[Math.max(...nums), Math.min(...nums)];
}

nums = [1, 4, 100, 5, 904580259, 40]
let x = getMaxMin(...nums);

let [max, min] = getMaxMin(...nums);

クラス

定義方法

  • constructorで初期値を定義する
class Member {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  getName() {
      return this.firstName + this.lastName;
  }
}

  • 関数として呼び出すことは不可能
  • 定義前のクラスは呼び出せない
let m = Member("foo", "bar");

class Member {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  getName() {
    return this.firstName + this.lastName;
  }
}

静的メソッド(特異メソッド)を定義する

  • staticで定義する

class Member { constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  static greet() {
    return "hello"
  }
}

継承する

  • extendsで継承
class Actindi extends Member {
  static service() {
    return "iko-yo";
  }
}

基底クラスのメソッド/コンストラクターを呼び出す(super)

  • superで基底クラスを継承 or 上書き

書き方

// construcor
super(args)

// method
super.method();
class Actindi extends Member {
  constructor(firstName, lastName, post) {
    super(firstName, lastName);
    this.post = post;
  }

  getName() {
    return this.post + super.getName();
  }

}

モジュール

  • exportでアクセスできるようにする

utility.js

export class Member {
  ...
}

export class Actindi {
  ...
}
  • importで取り込む
import { Member, Actindi } from './utility'

let m = new Member("foo", "bar");

importの記法

  • モジュール全体をまとめてインポート
    • asでモジュールの別名を指定しておく
import * as app from './utility'

let m = new app.Member("foo", "bar");
  • モジュール内の個々の要素に別名を付与する
import { Member as MyMember, Actindi as Act } from './utility'

let m = new MyMember("foo", "bar");

メソッド編

配列

for..of(配列を取り出す)

過去

let nums = [1, 2, 3];

for(var i = 0, len = nums.length; i < len; i++){
  console.log(nums[i]);
}

現在

let nums = [1, 2, 3];

for (num of nums) {
  console.log(num);
}

オブジェクト

assign

  • 同名のプロパティは後のもので上書きされる
let x = { name: "foo",
          email: "foo@foo.com",
          login: "var" }

let y = { name: "bar" }
let z = { title: "baz" }
Object.assign(x, y, z)
x
=>Object {name: "bar", email: "foo@foo.com", login: "var", title: "baz"}

処理

Strictモード

  • 「仕様として存在するが、安全性や効率面で利用すべきでない構文」を通知する
分類 Strictモードによる制限型
変数 var命令の省略禁止
変数 将来的に追加予定のキーワードを予約語に追加
変数 引数/プロパティ名の重複を禁止
変数 undefined/nullへの代入を禁止
命令 with命令の利用禁止
命令 arguments.calleeプロパティへのアクセスを禁止
命令 eval命令で宣言された変数を、周囲のスコープに拡散しない
その他 関数配下のthisはグローバルオブジェクトを参照しない(undefinedとなる)
その他 「0〜」の8進数表記は禁止

RubyKaigi2016 3日目レポート

2016年09月26日
区分
ruby
報告者:
endo

こんにちは、endoです。

3日目のレポートになります。

ホテルの感想

まずはホテルの感想から始めます。

食堂が刑務所みたいな雰囲気を感じ、個人的には好きでした。 初日はwifiが繋がらない部屋に当たり、すぐさまフロントに電話をして部屋の移動を願い出ました。

なお、同じ階の部屋移動するだけでwifiが繋がるようになりました。 なんだったんだ、あの部屋は・・・

ホテルのフロントの方の対応が良く、満足しました。 トラブル起きた時の対応が親切だと、よかったなって思えますね。

では、レポートを開始します。

Ruby Committers vs the World

Ruby Committersの質疑応答

gitに移行しないの?

redmineとsvnが連携しており、それを紐解いていくほどの効果が見受けられない。 実際にCommiterはgitで運用をしており、現状での管理に問題があるとは認識していない。

Python3のリリースはどう思いますか?

互換性を保つようにしたい 見習うところはあるので、そこは見習うようにする

rbenvのような機能は?

rbenvはrubyの外側なので、rubyに入っても嬉しくないと思う

Ruby3x3: How are we going to measure 3x?

発表者:Matthew Gaudet

正しいベンチマークの取り方

CPU・温度によっても変化する。 タイポで早くなったと勘違いすることがある。

High Tech Seat in mruby

発表者:Yurie Yamane

mrubyでウォッシュレットを作る

状態遷移は開始位置によって、結果が異なったりする。 ロゴブロックでデモをしてくれました。 ガチの組み込み系の話でした。

It’s More Fun to Compute

発表者:Julian Cheal

rubyで音楽を奏でる

rspecの結果により、音を出したり出さなかったりして、メロディーを奏でる その他にもアルゴリズムで音楽を作成していました。

Optimizing Ruby

発表者:Urabe, Shyouhei

rubyの処理速度を早くする

メソッド実行時に処理の最適化がされていない部分がある。 最適化できる部分は最適化をして、処理速度を早めた。

Dive into CRuby

発表者:NARUSE, Yui

Crubyへの関わり方

新機能(メソッドの追加や既存メソッドの拡張)、最適化、トラブルシューティング補助などがある。

新機能は必要?

rubyにtouchを入れてほしいという要望があった。 ファイルの更新時刻を変更したいからです。 touchには次のような効果があります。

  • ファイルの更新時刻を修正する
  • ファイルを作成する

touchだと、余計な機能が入るのでお互い不幸になるという話でした。

感想

自分は初参加でしたが、普段話すことはないだろうエンジニアの方たちと交流ができて楽しかったです。

コードについては、rubyの仕組みの部分が大きく占めていたので、調べておけばよかったなと思ってます。 単純に書くだけではなく、なぜ必要になったのかの背景があるとメソッドの使う場面がわかりやすくなると思うので、言語の部分を今後は学んでいきたいと思います。

英語はエンジニアにとって必須科目のようなものなので、ここは普段からなんとかしたい・・・orz

Ruby会議に参加してから、OSSに貢献してみようかな?と思い、gem作ったり、使用したgemにpull reqを送るようになりました。 自分の中でプログラミングに関わる意識の変化があったので、参加してよかったです!

補足

現在では公式サイトから講演が見ることができます。 参加することができなかった人や、もう一度聞きたいという方にはピッタリですね。

RubyKaigi初日レポート

2016年09月15日
区分
ruby
報告者:
endo

こんにちは、endoです。

今回は「RubyKaigi2016」に参加したレポートになります。 当社では、RubyKaigiの費用の「チケット代」「交通費」「宿泊費」「懇親会」は全て会社で負担していただきました。 このような対応をしていただいた会社と、出張している間に業務を行ってくれたチームメンバーに感謝です!

では、初日のレポートを行っていきます。 なお、講演は英語が多く、内容を把握するのに苦戦しました(´・ω・`)

英語は重要だ・・・orz

Ruby3 Typing

発表者:Yukihiro “Matz” Matsumoto

Ruby3の目指す方向性

  • パフォーマンス
  • 並列処理

今回はこの中でも「型」についてのお話でした。

ダックタイピング

Rubyにはダックタイピングと呼ばれる考え方があります。 「アヒルのように歩き、アヒルのように鳴くものはアヒルに違いない」という考え方です。 ダックタイピングは柔軟性が高く、期待される振る舞いのみを考えればいいです。 期待される行動は、自分たちの頭の中にあります。

動的型言語のデメリット

実行するまでエラーかどうかがわからない。 エラーメッセージが親切ではない。 エラーが起こるかどうかわからないので、テストでカバーするようになっている。 静的型言語はメソッドに型が書かれているので、どのような値が必要かどうかがわかる。

型を導入する方法

型はほしいけど、型を記入することは避けたい。 現状の型推論ではない方法での、型推論を導入する。 100%の精度はできないが、0→80%までの精度になれば、ないよりはマシになる。 失敗した場合は、元に戻せばいい。

リリース時期

ケネディ大統領が月に行くという目標を定めてから、実現した。 目標は必要。 東京オリンピックが始まる頃にはリリースしておきたい。

dRuby in the last century.

発表者:Masatoshi SEKI

RubyとWebをつなぐ

HTTPをアプリに埋め込むことを楽しんでいた。 RubyとWebをつなぐ作業をしていて、翻訳作業をすることが嫌になってきた。

dRubyの紹介

分散オブジェクトシステム プロセス越しにメソッドが呼べる プロセス間でオブジェクトが送れる

Welcome to haconiwa - the (m)Ruby on Container

発表者:Uchio KONDO

haconiwa

mRubyで作成したコンテナ技術 もともとはCRubyで作っていたがsyscallsの限界があり、mRubyに書き換えた。

haconiwaを作った背景

docker/lxcでバグに遭遇したが、なかなか理解できなかった。 コンテナ技術を理解するためにhaconiwaを作成。

A proposal of new concurrency model for Ruby 3

発表者:Koichi Sasada

rubyの並列処理について

rubyの並列処理はGVL(Giant VM Lock)の関係でI/O待ちが発生している このため、rubyの並列処理は遅いということがよく言われる

guild

rubyの並列処理を早くするための新しい概念 GVLを解放することで、並列処理を早くするようにする

Isomorphic web programming in Ruby

発表者:Yoh Osaki

railsでreact likeに書けるようにする

jsが嫌いなので、rubyでreactを使いたいということで、作成 デモ講演を披露してくれました

Scalable job queue system built with Docker

発表者:Takashi Kokubun

Job Queueシステムを作成

カジュアルにJobが実行されていて、一元管理ができていなかった。 一元管理をするために、新しいJob Queueシステムを作成した

懇親会

この後は懇親会がありました。 個人的には海外の参加者の方と話をしてみようと思い、海外の参加者の方に話しかけていました。 ただ、日本語が普通に喋れる方だったので、日本語で会話をしていましたorz

海外の参加者の方との交流も図れるのがいいですね!

ちなみに自分がお話をした海外の参加者の方は、普段使う言語がPython・Goでした(`・ω・´)

こういう方でも参加しているのに驚きました。

初日感想

ノベルティが配布され、自分はステッカーを漁りまくっていました。 ブースではコーヒーが飲み放題で、交流も図れるので情報交換ができました。 このような対応していただいたスタッフの皆様に感謝です!

コミッターの方々は当たり前のように英語で話をするので、レベル差を感じました。 なんで英語そんなにできるんだ・・・

あと、見ている層が違うんだなーと感じた1日でした。

現場からは以上です。

ソースコードの向上

2016年04月20日
区分
ソースコード
報告者:
endo

こんにちは、endoです。

4月11日より、アクトインディに入社しました。

このブログに書き込みができることに、嬉しさを感じております。

早く一人前になるように頑張ります。

本日は、ソースコードについて指摘を受けたので、その話を書きます。

・グローバルにアクセスするインスタンス変数を、グローバルにアクセスする場所に書くのは良くない

たとえば、下記のようなコードがあったとします。

app/application_controller.rb

before_action user_list
def user_list
  @users = User.all
end

app/application_helper.rb

def user_newlist
  @users.order('id DESC')limit(10)
end

この場合、何らかの変更でuser_listが廃止されたとします。

その場合、user_newlistまで影響してしまいます。

こういうメソッドをあちこちに散らかしていると、変更があった場合の影響が計り知れません。

簡単にアクセスできるから、動けばいいじゃん!みたいなコードを書いてしまうと後処理が大変になります。

今はソースコードレビューを受けて、レベルが上がっていくのが嬉しいです。

何はともあれ、クソコード(・A・)イクナイ

技師部隊からの
お知らせ

【求人】エンジニア募集しています。

本頁の来客数
八十七万千百七十六名以上(計測停止中)

メンバー一覧

アクトインディ技師部隊員名簿

アクトインディ技師部元隊員

アクトインディへ

カテゴリー

アクトインディ

aaaa