今川館

都内勤務の地味OLです

SQLServerでランキングを求めるとき -- OVERの使い方(OLAP関数)

「最後に買ったもの」を調べる

SQLで「誰が・何を・いつ買った」という買い物データから「その人が最後に買ったもの」を調べようとすると案外難しい。

データイメージ

PERSON	GOODS	PURCHASE_DATE
+-------+-------+--------------
Tom	Orange	2015-2-19
Tom	Apple	2015-2-17
Nancy	Apple	2015-2-19
Nancy	Potato	2015-2-17

期待する結果

PERSON	GOODS	PURCHASE_DATE
+-------+-------+--------------
Tom	Orange	2015-2-19
Nancy	Apple	2015-2-19

MAXのA列に該当するレコードのB列といったデータを取り出してくださいと言われて少々答えに窮したのでここにメモしておく。

こういうデータを取り出すときは相関サブクエリかOLAP関数を使うとできる。
おすすめはOLAP関数を使うやり方で、相関サブクエリを使うとどうしてもSQL文が読みにくくなる。

続きを読む

SQLServerの文字列と日付の暗黙的型変換

文字列型からDATE/DATETIME型への暗黙的型変換

SQLServerは文字列型の値をDATEやDATETIMEで評価する必要がある場合は暗黙的に型変換を試みる。

クエリ1

SELECT MAX(foo) foo FROM (
    SELECT '2015-2-13' foo
    UNION ALL SELECT '2015-2-14' foo
    UNION ALL SELECT CONVERT(DATE, '2015-2-12') foo
) x

結果

foo
2015-02-15
続きを読む

setup.pyのdependency_linksの書き方

前回の続き


前回の記事
でpipコマンドにGithubリポジトリsshで接続するURLを指定する方法を紹介した。

今度はsetup.pyで非公開プロジェクトを依存パッケージに指定する方法をここにメモしておく。

なお、わたしはwheelパッケージの仕様を知らないのでここでは旧式のeggパッケージを作ることを想定して話を進める。

続きを読む

pipでGithubにssh接続して非公開リポジトリをインストールする

非公開リポジトリのパッケージをインストールするのは難しい

自社のプライベートプロジェクトを別のプロジェクトから利用したい場合、簡単にpipやeasy_installでインストールできず困ることがある。

続きを読む

AnsibleのHost Variablesの使いどころ

Host Variables とは?

Inventory — Ansible Documentation

[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909

Host Variablesは上記引用の通り、インベントリのホストのセクションに併記する値なのだが、これの使いどころって何なんだろうと最初のころ疑問に思っていた。

なぜならAnsibleはインベントリ以外にも変数に値を渡せる箇所がたくさんあるからだ。

ところがAnsibleを使い込んでいくうちにHost Variablesを使った方がうまくいくケースが存在することが次第にわかってきた(以下)。

特定の環境だけSSHの接続情報が違うとき

例えば

  • development.ini 開発環境のDB/サーバーの設定値
  • production.ini 本番環境の設定値

このように環境別にインベントリを分けて管理する場合に、特定のサーバーだけSSHに2022番ポートで接続しなければならないときにHost Variablesは役立つ。

[development.ini]

[webservers]
192.108.22.3  ansible_ssh_port=2022
192.108.22.6

[production.ini]

[webservers]
192.108.25.35
192.108.25.36

こんな風に。

複数のサーバーで冗長化しつつも、master/slaveの役割分担しているとき

本番環境に1号機と2号機の2台サーバーを用意してそれぞれwebアプリを稼働させるけれども、1号機にはcrontabを設定しバッチサーバーとしても稼働させる場合を想定する。

そして、もし1号機が故障したら2号機をバッチサーバーとして動かす運用とする。

つまり

[通常時]

サーバー web バッチ
1号機
2号機 ×

[1号機 障害時]

サーバー web バッチ
1号機 - -
2号機

このように構成を変える運用を想定する。

こういうときもHost Variablesが役立つ。

[roles/batch-server/tasks/main.yml]

- name: とあるジョブ {{ switching }}
  cron: name='some job'
        job='cd /var/www/some/src; /var/www/some/bin/python manage.py somejob'
        user=www
        hour='*/1'
        minute=5
        state={{ 'present' if switching == 'on' else 'absent' }}
  sudo: yes

[build.yml]

- hosts: servers
  roles:
    - { role: batch-server, switching: 'on', when: master == 'yes' }
    - { role: batch-server, switching: 'off', when: master != 'yes' }

[production.ini]

[servers]
192.168.22.3  master=yes
192.168.22.7  master=no
実行コマンド
$ ansible-playbook -i production.ini build.yml

上記コマンドでデプロイする。
もし障害が起きて1号機が使えなくなったらproduction.iniを

[servers]
# 192.168.22.3  master=no
192.168.22.7  master=yes

このように2号機をmaster=yesと書き換えて同じコマンドでデプロイすれば簡単にcrontabを仕掛けたり外したりできる。

Ansibleのハンドラが起動するのはタスクがchangedを返したときだけ

Ansibleのハンドラとは

Ansibleのタスクには `notify` という属性を追加してコールバック処理を呼ぶよう設定できる。

[roles/nginx/tasks/main.yml]

- name: nginx config ensure
  template: src=my.nginx.conf.j2 dest=/etc/nginx/conf.d/your.conf
  sudo: yes
  notify: restart nginx

[roles/nginx/handlers/main.yml]

- name: restart nginx
  service: name=nginx state=restarted
  sudo: yes

こう書いておくと roles/nginx/templates/my.nginx.conf.j2 から生成した内容が /etc/nginx/conf.d/your.conf の内容を変更したときに、自律的にnginxを再起動してくれる。

この挙動を一般に「nginxの設定を変えたら自動的に再起動される」などと呼ぶ。

ところがわざわざ下線を引いたけれども、Ansibleのプレイブックを実行したタイミングで `nginx config ensure` のタスクが `CHANGED` を返さないとハンドラは起動しない。

だから

  1. プレイブックを起動。(A -> B -> C) の順にタスクを実行。
  2. nginxの設定ファイル配置をBのタイミングで行ったが、Cに指定した別のタスクが失敗した。
  3. ハンドラはすべてのタスクが終わった後に動くのでCが失敗した時点で処理が終わってしまう。
  4. もう一度プレイブックを動かすとBのタスクではもはやCHANGEDとは評価されないのでnginxが再起動されないまま放置される。

このような事態が起きうる。

役に立つのかわからない --force-handlers オプション

そういう事態を想定して、 `ansible-playbook` コマンドには `--force-handlers` というオプションが用意されている。

これを指定してプレイブックを動かすと、たとえタスクが失敗してもハンドラの起動まで進めてくれる。

とはいえ、指定し忘れると結局アウトなのだ。

よくわからないのだが、Ansibleには「ハンドラのタスクを指定して動かす」仕組みが無いので、nginxの設定ファイル配置以降のタスクが予期せず失敗した場合にやり直す方法が無い。

どうしたらいいのか?

仕方が無いのでこんな方法で対処してみた。

Role -- register/changed を利用

[roles/nginx/tasks/main.yml]

- name: 1. nginxの設定ファイルを配置
  template: src=my.nginx.conf.j2 dest=/etc/nginx/conf.d/your.conf
  sudo: yes
  register: nginx_conf
  notify: restart nginx

... (他の雑多なタスク) ...

- name: 2. nginxが起動していること
  service: name=nginx state=started
  sudo: yes

- name: 3. nginxを強制的に再起動
  service: name=nginx state=restarted
  sudo: yes
  when: nginx_restart is defined and not nginx_conf.changed
  tags:
    - deploy
実行コマンド

[通常時]

$ ansible-playbook -i foo.ini some.yml

[やり直しするとき]

$ ansible-playbook -i foo.ini some.yml -t deploy -e 'nginx_restart=yes'

こうしておけば

  • 1のタスクでnginxの設定が変わったらハンドラから再起動される
  • 3のタスクはコマンドラインからnginx_restartを指定したときだけ動く
  • 1から動くハンドラと3のタスクによってnginx再起動が2度実行されることもない
ひとり言

なんかややこしいことをしている気がするのだが・・・
もっと簡潔な方法は無いのか。