マスコットアプリ文化祭でこのはちゃんとあんずちゃんのアプリを作った話

この記事は、ConoHa Advent Calender 2016の16日目の記事です。

qiita.com

技術的な内容メインじゃないのでQiitaじゃなくてこっちに書きます。 ConoHaにはCoreOSをインストールしていて、DockerでWebアプリをデプロイしてたりします。

マスコットアプリ文化祭とは

企業や団体のイメージキャラクターを使った作品のコンテストです。 作品はアプリに限らず、イラストや動画でもOKな感じになっています。

mascot-apps-contest.azurewebsites.net

このマスコットアプリ文化祭で2014年と2016年はConoHaがスポンサーをしていたため、このはちゃんやあんずちゃんのアプリを作りました。 もちろんどちらのアプリもConoHaで動かしています! それにしてもいつもこのはちゃん負けてますね

f:id:abcang:20161214011055p:plain

mikumo.abcang.net

f:id:abcang:20161214011123p:plain

stamp.mikumo.abcang.net

みくもファンクラブ

これは2014年に作った作品で、ConoHa byGMO賞に選ばれました! このアプリは「このはちゃん大好き!」と「あんずちゃん大好き!」と書かれたボタンが設置されており、 これを押すとカウントが増えてキラキラ光るようになってます。 それと同時に、このサイトを見ている他の人の画面でもカウントが増えてキラキラ光ります。 このはちゃん派とあんずちゃん派でクリック合戦が始まり、両者とも1000万を超えてしまいました。

実装はNode.jsを使っています。 当時自分が使ってみたかったという理由だけでSailsを使っており、 またデータベースも特に何も考えずにmysqlを使っていたため、大量にクリックされたときの負荷がすごかったです。 やばいときはCPUフル稼働でした。

現在はSailsとmysqlをやめて、socket.ioとredisで動かしています。(みくもスタンプを作った後に作り直しました。) みくもファンクラブはDockerのnginx-proxy経由で動かしています。 以前はみくもファンクラブのコンテナだけがCPUを使いまくっていましたが、 改善後はnginx-proxyもCPUを多く使うようになったので、だいぶ高速化されました。 1秒あたり1000クリックがあってもわりと余裕で捌けるようになっています。

ソースコードを公開しているので気になる人はどうぞ。

github.com

みくもスタンプ

これが2016年に作った作品です。 このアプリは名前の通りみくもスタンプ(LINE版もあります)をお試しできるというものです。 みくもファンクラブみたいに大量クリックでスタンプ爆撃ができるようにと想定して作ってあります。 しかし、なんかみくもファンクラブの方が盛り上がっちゃって、あまり利用されてない感じがします。

実装はみくもファンクラブと同様にNode.jsで作っています。 WebSocket周りの実装をする時はsocket.ioが便利というところが大きいですね。 こちらもソースコードを公開しているので気になる人はどうぞ。

github.com

詳しい実装とか

みくもファンクラブとみくもスタンプはほぼ同じような実装なので、みくもスタンプの実装について書いていきます。 みくもファンクラブは以下のライブラリとかで構成されてます。

  • Node.js v7
  • redis
  • koa 2
  • socket.io
  • harp
  • Vue.js

ざっくり説明すると、koaで書いたサーバにsocket.ioに繋いで、データはredisで管理しています。 htmlはharpであらかじめビルドしたものを配信しており、 フロントはVue.jsで書いています。

harpとkoa

まずharpについてですが、これはnode製の静的サイトジェネレータです。

harpjs.com

cssじゃなくてsassとかで書きたかったのと、htmlの内容を開発環境と本番環境で変えたかったので使ってみました。 javascriptのminifyはしてくれなかったので、そこはしかたなくuglifyjsを直接使うことにしました。 glup書きたくないマンなので、npm scriptに仕込んで使っています。

{
  "scripts": {
    "build": "harp compile client/src public && uglifyjs -c -o ./public/js/app.min.js ./public/js/app.js"
  }
}

harpはコマンドでビルドしたり開発用のサーバを立てたりするだけでなく、 expressのmiddlewareとしても利用することができます。 今回はexpress用middlewareをkoa向けに変換してくれるkoa-connectを使用しました。 npmで提供されているバージョンは少し古く、koa 2で使用するためにはgithubのコードを使用する必要がありました。

koa周りのコードは以下のような感じになってます。 コード的には本番環境ではkoa-staticでファイルを静的配信するようになっていますが、 実際には静的ファイルはnginxが配信していて、koaの機能はあまり使ってません。 開発時にはharpをkoaで使うようにしています。 また、socket.ioはkoa経由で動くようにしています。

const app = new Koa();

if (process.env.NODE_ENV === 'production') {
  app.use(serve(path.resolve('./public')));
} else {
  console.log('development mode');
  app.use(serve(path.resolve('./client/src')));
  app.use(c2k(harp.mount(path.resolve('./client/src'))));  // 開発時はharp経由で
}

const server = app.listen(process.env.PORT || 3000);
const io = require('socket.io').listen(server);

Node.js v7とredis

Node.js v7からasync awaitが使えるようになった(フラグを指定する必要がありますが)ので、バンバン使ってみました。 感想としては、めちゃくちゃきれいにコードが書けて最高という感じでした。

const [stampsData, anzuCount, mikumoCount, conohaCount] = (await redis.multi()
  .lrange('stamps', 0, 49)
  .get('count:anzu')
  .get('count:mikumo')
  .get('count:conoha')
  .exec()).map((res) => res[1]);

このコードはアクセス時に現在のデータを取ってくる処理です。 redisへのアクセスはPromiseが使用できるioredisを使っています。 トランザクション処理もこのようにawaitと分割代入を使ってスッキリと書けました。

// 消えたスタンプの既読キーを削除
(await redis.hkeys('views')).reduce((pipeline, id) => {
  if (stampIds.includes(Number(id))) {
    return pipeline;
  }
  return pipeline.hdel('views', id);
}, redis.pipeline()).exec();

このコードでは、redisから取得した配列に対してreduceメソッドを実行しています。 async awaitがないとここまできれいには書けないですね。 余談ですが、redis.pipeline()はPromiseを返して、hdelなどのメソッドを実行してもPromiseを返してくれるので、 Array.prototype.reduceを使うとパイプラインを繋ぎやすくて非常にいいですね。

フロント側のコードとVue.js

この小規模なアプリでbabel使うのもなーということで、 フロント側のコードはES5で書きました。 そしてライブラリなどはcdnのものを使うようにしています。

今回ずっと気になっていたVue.jsを初めて使ってみました。 Vue.js 2系使いはじめて数日経った時に丁度2系向けの日本語ドキュメントが出て非常に助かりました。 Vue.js 2系からコンパイルするということもできるようになっていますが、 webpackとかもあまり入れたくないなーということで、今回は普通にhtml内に書くことにしました。

また、Bootstrap大好きマンなのでvue-strapを使用しています。 ただ、Vue.js 2系向けのは現在開発中でpreview版がgithubから使える状態になっているため、 今回はそれを使用しています。 正式公開されてcdnとかで配信されるようになったら修正しようかなと思ってます。

おわりに

アプリの紹介も少しだけで、なんだか何を言いたい記事なのかよくわからない感じになってしまいましたが、 とりあえずアプリで遊んでみてくださいってことで終わろうかと思います。

mikumo.abcang.net

stamp.mikumo.abcang.net

ConoHaカード クーポン付き

ConoHaカード クーポン付き