hirapi's blog

ちゃんとしたふりをする

jsだけレスポンスヘッダで文字コードを設定する @Apache

Apacheでjsが文字化けした。

ファイルの文字コードも無茶苦茶だしApacheよくわかんないしあーあーしてたら先輩が解決してくれた、自力で見つけられなくて悔しかったから書いとく。

直接の原因はjsファイルはUTF-8だったのにレスポンスヘッダを見るとEUC-JPが指定されていたこと(PHPのファイルがEUC-JPだったから?

というわけでjsはUTF-8で開いてほしい → .htaccess があったからそれにこう書いて終わり。

AddCharset utf-8 .js

今回言われるがままに .htaccess に追記したけど積極的に使うべきものではないのかな↓↓

Apache チュートリアル: .htaccess ファイル - Apache HTTP サーバ バージョン 2.4

一般的に、サーバの主設定ファイルにアクセスできない場合を除いて、 .htaccess ファイルの使用は極力避けてください。

複数のユーザーがどうしても自分の好きに設定したいときに各人作るものらしい。
リクエストのたびに .htaccess のファイル探すコストがかかるのと、ユーザーがwebサーバーの設定をいじくれる状態はよくないのと、というところだそう。

というかApache + PHP、どこで何が起きてるのかわからなすぎて苦手。nginxのほうがまだがんばれる。。。

ネットワーク調査あれこれメモ①

会社でなんか変だぞーって調べてたときに打ったやつとか参考にした記事とか、何度か同じこと調べてるので残しておく。
誰の利にも別にならないことを書いておけるのは個人ブログの良いとこだと思う。
予定は無いけど②とか③とか生まれる気がするから①(YAGNI!!)

状態ごとの接続数

[hirapi@server ~]$ netstat -tan | awk '{print $6}' | sort | uniq -c
      4 CLOSE_WAIT
     88 ESTABLISHED
      1 FIN_WAIT2
      1 Foreign
     12 LISTEN
   2598 TIME_WAIT
      1 established)

規定時間以上残っているTIME_WAIT

[hirapi@server ~]$ netstat -nato|egrep -c 'timewait. *\(0.00'
2001

TIME_WAITに関する話

半分以上わからなかったけどこちらのスライドありがたかった、kernel 3.Xだとうまく回収してくれないのね。。。

ついでにカーネルのバージョン確認は

[hirapi@server ~]$ cat /proc/version
Linux version 2.6.32-358.el6.x86_64 (mockbuild@c6b8.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) ) #1 SMP Fri Feb 22 00:31:26 UTC 2013

[hirapi@server ~]$ yum list installed | grep kernel
dracut-kernel.noarch               004-409.el6_8.2            @updates
kernel.x86_64                      2.6.32-358.el6             @anaconda-CentOS-201303020151.x86_64/6.4
kernel.x86_64                      2.6.32-696.18.7.el6        @updates
kernel-devel.x86_64                2.6.32-642.4.2.el6         @updates
kernel-devel.x86_64                2.6.32-696.18.7.el6        @updates
kernel-firmware.noarch             2.6.32-696.18.7.el6        @updates
kernel-headers.x86_64              2.6.32-696.18.7.el6        @updates

(開発環境だから……)

recycleとreuse

net.ipv4.tcp_tw_recycle は廃止されました ― その危険性を理解する - Qiita

ロードバランサの配下にある通信ではパケットに振られるタイムスタンプ(の前後関係)が実時間と一致しているかわからないため、タイムスタンプで新旧を判断するrecycleを有効にすると意図しない切断が起こる可能性がある、とのこと?

TCP関連のカーネルの設定ファイル

/etc/sysctl.conf
変更はこれ書き換えてから # sysctl -p

ローカルポートを広げる

接続数多すぎてなんか止まっちゃった、という時はローカルポートを使い切っている可能性を疑う。変更は↑↑の設定ファイルのここ

net.ipv4.ip_local_port_range = 20000 65500

ローカルポートを食いつぶしていた話 - ダウンロードたけし(寅年)の日記

サーバーとかネットワークとかぜんぜんわからずにアプリケーション書くと最後はこういうとこで詰まってお手上げになる。
平気で6万回もMySQLサーバーに繋ぐ画面なんて作らないでよ過去の人……。
とはいえちょっとだけ低レイヤー(?)に興味を持てた、Linuxとかネットワークとかちょこちょこ読書中。

redashの入力フォームで「特定の値 -> 無指定」として扱いたいときのSQL

redash.io

こんなテーブルがあったとして、

mysql> SELECT * FROM users;
+----+-----------+------+----------+
| id | name      | age  | group_id |
+----+-----------+------+----------+
|  1 | hirapi    |   25 |        1 |
|  2 | someone   |  100 |        1 |
|  3 | young man |    6 |        2 |
+----+-----------+------+----------+

redashの入力フォームに「対象グループID」を入力して、そのグループの人の名前を取ってきたいとする。 redashは {{フォーム名}} で入力値を取れるので、普通に書くと

SELECT name FROM users WHERE group_id = {{対象グループID}}

となる。

ここで、例えば「グループ関係無くみんなの名前も取れるようにしたい、クエリは分けたくない」みたいなこと言われたら、 「入力フォームに 0 を入れたらグループ無指定ということで全員の名前を取ってくる」というのはどうだろうということになる。

pythonでif文はさんでクエリ作るのもアリといえばアリだけど面倒くさいなあと思った結果↓↓

SELECT name FROM users WHERE {{対象グループID}} = 0 OR group_id = {{対象グループID}}

対象グループID が0だったら

mysql> SELECT name FROM users WHERE 0 = 0 OR group_id = 0;
+-----------+
| name      |
+-----------+
| hirapi    |
| someone   |
| young man |
+-----------+

対象グループID が1だったら

mysql> SELECT name FROM users WHERE 1 = 0 OR group_id = 1;
+---------+
| name    |
+---------+
| hirapi  |
| someone |
+---------+

クエリチューニングの面から見たら良くないかもしれないけどさくっと作れたし今回はおっけー。
別にredashに限った話ではないけど入力値をそのままクエリに突っ込むのがredashくらいしかなかった。

Prestoで配列の要素数を取得する

6.15. Array Functions and Operators — Presto 0.195 Documentation

cardinality(x) → bigint

Returns the cardinality (size) of the array x.

countとかsizeとかかなあと思ってたら違った、カーディナリティか……

入れ子配列のカラムを指定しても入れ子は展開されずに、なんていうかふつうにカウントされた。

PHPでTreasure Dataにpost2()

会社でTreasure Dataを使ってログの蓄積・集計をしていて、PHPからTreasure Dataにレコードを送ることがある。
そういうときはこのライブラリを使う↓↓

github.com

今まではこのREADMEにあるUsageのとおりこんな感じで送ってた↓↓

<?php

require_once __DIR__.'/vendor/autoload.php';

use Fluent\Logger\FluentLogger;
$logger = new FluentLogger("localhost","24224");
$logger->post("debug.test",array("hello"=>"world"));

ただこの間ちょっとレコード多くなるかもだから集計時間短くなるようにしたいなということがあって、こちらのブログを参考にtimeカラムに ID × 3600 みたいな任意の値を入れたくなった。

yebisupress.dac.co.jp

やってみて気づいたんだけど、こういう配列を前述の例のように post() に渡してもtimeカラムにはunixtimeが入ってしまう。

<?php

require_once __DIR__.'/vendor/autoload.php';

use Fluent\Logger\FluentLogger;
$logger = new FluentLogger("localhost","24224");
$logger->post("debug.test",array("time"=>7200)); // => timeカラムには普通に呼び出し時のunixtimeが入る

GitHubpost() のところを追ってみたところ、timeカラムの値は別途自動で入れられるらしい。

じゃあこのライブラリではtimeカラムに好きな値を入れられないかというと、そういうわけではない。

ここで post2()の出番。
冗談みたいな名前してるけどpublicなメソッド。

post() にはタグと配列を渡すけど、 post2() にはEntityクラスインスタンスを渡す。
post() も中身を見たら同じことをやっている。
Entityクラスのコンストラクタを見ると、第三引数にtimeっぽい値を渡せるとのこと。
post() の中身ではここに何も渡してないからデフォルトでnullになって、結果Entityオブジェクトのtimeプロパティにそのときの時刻が入る、というだけらしい。

というわけで自分でEntityクラスのインスタンスを作って post2() に渡してあげるとtimeカラムにちゃんとその値が入る。

<?php

require_once __DIR__.'/vendor/autoload.php';

use Fluent\Logger\FluentLogger;
use Fluent\Logger\Entity;
$logger = new FluentLogger("localhost","24224");
$entity = new Entity("debug.test",array("hello"=>"world"), 7200); // 第三引数にtimeカラムの値
$logger->post2($entity); // => timeカラムに7200が入る

レビューで先輩に教えてもらったとき何だその名前、と思ったけど合ってる。
どういう名前をつけるのがいいのかなあとちょっとだけ考えてみたけど、そもそもなんで送信用のメソッドを2つ作ったのかにもよるのかもしれない?

名前にちょっとだけウケたから投稿してみた。

Hanami公式入門ガイド日本語訳【5】Getting Started(4)

http://hanamirb.org/guides/1.1/getting-started/#writing-our-first-test

初めてのテストを書く

ブラウザでアプリケーションを開いたときに最初に目にする画面は、ルーティングが何も定義されていないときに表示されるデフォルトページです。

HanamiはWebアプリケーション開発手法としてビヘイビア駆動開発(BDD)を推奨しています。
最初の自作の画面を表示させるために、高次元の機能テストを書きましょう:

# spec/web/features/visit_home_spec.rb
require 'features_helper'

describe 'Visit home' do
  it 'is successful' do
    visit '/'

    page.body.must_include('Bookshelf')
  end
end

注意してほしいのは、Hanamiは最初からBDDの開発フローをサポートしていますが、特定のテスト用フレームワークに縛られているわけでもなければ、特別な統合システムやライブラリを備えているわけでもありません。

ここではMinitest(デフォルト)を使っていきますが、プロジェクトを作る際に --test=rspec オプションをつけることでRSpecを使うこともできます。
そうすればHanamiはRSpecのためのヘルパーやスタブのファイルを生成します。
(※ データベースのURLを微調整する必要があるときは .env.test を確認してください)

このコマンドを実行して、テスト用のデータベースにスキーママイグレーションしなければなりません:

% HANAMI_ENV=test bundle exec hanami db prepare

見ての通り、コマンドを実行する環境を指定するには環境変数 HANAMI_ENV をセットします。

リクエストを受ける

今テストを実行すると、失敗することがわかります:

% bundle exec rake test
Run options: --seed 44759

# Running:

F

Finished in 0.018611s, 53.7305 runs/s, 53.7305 assertions/s.

  1) Failure:
Homepage#test_0001_is successful [/Users/hanami/bookshelf/spec/web/features/visit_home_spec.rb:6]:
Expected "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Not Found</title>\n  </head>\n  <body>\n    <h1>Not Found</h1>\n  </body>\n</html>\n" to include "Bookshelf".

1 runs, 1 assertions, 1 failures, 0 errors, 0 skips

それではこのテストを通しましょう。
そのために必要な必要なコードをひとつずつ書き足していきましょう。

初めに足すのはルーティングです:

# apps/web/config/routes.rb
root to: 'home#index'

アプリケーションのルートを home コントローラの index アクションに指定しました(詳しくはルーティングの解説を見てください)。
次にindexアクションを作ります。

# apps/web/controllers/home/index.rb
module Web::Controllers::Home
  class Index
    include Web::Action

    def call(params)
    end
  end
end

これは何のビジネスロジックも実行しない空のアクションです。
それぞれのアクションには対応するビューがあり、ビューはRubyのオブジェクトであり、リクエストを満たすために追加する必要があります。

# apps/web/views/home/index.rb
module Web::View::Home
  class Index
    include Web::View
  end
end

アクションと同様にこのビューも空であり、テンプレートをレンダリングするだけです。
これが、テストを通すために編集する必要のあるファイルです。
先頭に "bookshelf" と追加するだけです。

# apps/web/templates/home/index.html.erb
<h1>Bookshelf</h1>

変更を保存し、テストをまた走らせてください。そうすると今度は通ります。
やったね!

Run options: --seed 19286

# Running:

.


Finished in 0.011854s, 84.3600 runs/s, 168.7200 assertions/s.

1 runs, 2 assertions, 0 failures, 0 errors, 0 skips

Hanami公式入門ガイド日本語訳【4】Getting Started(3)

http://hanamirb.org/guides/1.1/getting-started/#hanami-architecture

Hanamiのアーキテクチャ

Hanamiのアーキテクチャでは、同じRubyのプロセスで別々のHanamiアプリケーション(とRackアプリケーション)をホストすることができます。
これらのアプリケーションは /apps 以下にあります。
各アプリケーションが、ユーザー向けのWebページや管理画面、メトリクス、HTTP APIなどととしてプロダクトを構成することができます。

これらのパーツは、lib 以下にあるビジネスロジックに対する 分娩機構 (訳註:原文では" delivery mechanism ")です。
ここは、Modelが定義され、相互作用してプロダクトが提供する機能を構成するディレクトリです。

Hanamiのアーキテクチャクリーンアーキテクチャに強く影響を受けています。