ジョギング
- お休み
- 右足の太もも痛みが引き続き...
ギョーム
- Lambda の Node.js ランタイムバージョンアップを検証しながら
- LocalStack を使ってローカル環境で動かしてみてとか思ったけど, 意外に LocalStack がで Lambda を動かしたり, そもそも Serverless Framework を介したデプロイがうまく動かなかったり... なかなか骨が折れた
夕飯
とにかく太ももを早く治したいので, 牛もも肉の塊を食べた. ウェップ.
お疲れ様です. かっぱです. YAMAP に入社してもうすぐ一年が経とうとしています. あっと言う間の一年でした. この一年の振り返りを... と思いましたが, 最近の悩み事を技術で解決してみようと思って試験的に実装した内容を紹介させていただきます.
そして, この記事は, YAMAP エンジニア Advent Calendar 2019 の 25 日目の記事になる予定です.
YAMAP では, yamap.com 以外にもいくつかの外部サイトを運営しています.
これらのサイトのデプロイ作業を含む各種運用に携わっていますが, これらのサイトがデプロイの度にレイアウトがデグレしてたり, 意図しないような状態で表示されたりすることが多く発生していました. 原因はいくつかありますが, コンテンツが CVS の管理外であったり, コンテンツをオンラインで更新していて CVS にマージされていなかったり人為的な手違いによるものが多く, さらに, その異常に気付くことが出来なかったりして胃が痛くなる日々が続いていました. ということで, ざっくりと悩み事をまとめると...
こんな感じです.
下図のような実装を考えて実装しました. (雑に手書きですいません.)
流れとしては...
こんな感じ. 上図では Puppeteer ってなっているところは, 実際には Jasmine から Puppeteer を操作してスクリーンショットを取得して, 従来のスクリーンショットとの差分を比較する処理が動きます.
出来るだけ手を動かすことなく CircleCI 上で動かすことを考えました.
また, Puppeteer でサイトにアクセスしてスクリーンショットを取得して比較するコアな部分は最小限の実装に スクリーンショットを S3 にアップロード, ダウンロードする部分はコアとは別に AWS CLI (実際には CircleCI の orbs) で実装しました. 以下は .circleci/config.yml の抜粋です.
version: 2.1 orbs: aws-s3: circleci/aws-s3@1.0.11 slack: circleci/slack@3.4.1 executors: default: docker: - image: circleci/node:12.4 - image: circleci/python:2.7 commands: check_prepare: steps: - aws-s3/sync: from: s3://${ROOT_PATH}/ to: /home/circleci/project/${ROOT_PATH}/ overwrite: true arguments: > --delete npm_install: steps: - run: name: Update npm command: sudo npm install -g npm@latest - restore_cache: name: Restore Dependencies keys: - dependencies-{{ checksum "package-lock.json" }} - dependencies - run: name: Install Dependencies command: npm install - save_cache: name: Save Dependencies key: dependencies-{{ checksum "package-lock.json" }} paths: - node_modules jobs: check: executor: name: default steps: - checkout - run: name: Install Headless Chrome dependencies command: | sudo apt-get install -yq \ ... 略 ... - npm_install - check_prepare - run: name: Run test command: ./node_modules/.bin/jasmine ... 略 ... - run: name: Store Images command: | aws s3 sync /home/circleci/project/${ROOT_PATH}/ s3://${ROOT_PATH}/ when: always - slack/status: fail_only: true mentions: ${SLACK_MEMBER_IDS} workflows: version: 2 byhand-webpage-check: jobs: - check triggerd-webpage-check: triggers: - schedule: cron: "3 * * * *" filters: branches: only: - master jobs: - check
また, CircleCI の triggers を利用して一時間に一回定期的に実行させるようにしています.
さらに, S3 へのアップロードと Slack への通知は orbs を利用しています.
ちょっと痒いところに手が届かないところ (run
で利用出来る when
的な定義が書けないとか) が残念でしたが, 基本的な使い方であれば全然 orbs でいけるので最高ですな.
何よりも Puppeteer です. 全く触ったことなかったので, 見様見真似で写経 (コピペ) していました. しかし, 以下のように簡単にサイトのスクリーンショットを取得出来るのには感動しました.
// // https://github.com/puppeteer/puppeteer#usage より引用 // const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://yamap.com'); await page.screenshot({path: 'test.png'}); await browser.close(); })();
これを test.js あたりで保存して node test.js
とすると, 以下のようなスクリーンショットがシュッと撮れます.
しかし, 相手は JavaScript, 一筋縄ではいきません. async
と await
がよくわからないまま書き進めてしまい, 一応, 思ったような動作になりました... これでは, 成長が無いのでもう少し async
と await
をはじめ JavaScript について理解を深めていきたいと思います.
ページ全体のスクリーンショットを取得したい場合, 以下のように screenshot
メソッドの引数に fullPage: true
をつけてあげると取得出来ることは確認しました.
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://xxxx.xxxx.com/'); await page.screenshot({path: 'test.png', fullPage: true}); await browser.close(); })();
ところが, サイトによっては, 下図のように画像が一部読み込まれず悩みました.
現在も解決出来ていません...
差分抽出には Resemble.js を利用しています.
この Resemble.js も Puppeteer 同様に以下のように簡単に画像の差分を抽出することが出来ます.
resemble('after.png').compareTo('before.png') .ignoreColors() .onComplete(function(data) { fse.writeFileSync(DirName + 'diff.png', data.getBuffer()); });
CircleCi でのテスト結果.
上記のように, 対象ページに差分があり, 差分許容率がしきい値を超えるとテストが Fail となります.
Fail したら Slack に上図のように通知されます. 通知が届いたら, S3 バケットに保存されている画像を確認して, 意図した差分なので, そうでないかをデザイナーさん等に確認する流れになることを想定しています.
また, テストと合わせて差分抽出画像が生成されます. 差分抽出画像は上図のような画像になります. 前回のスクリーンショットとの差分がピンク色に着色された状態になります.
以下の記事を大幅に参考にさせていただきました. Puppeteer のことを 1bit もわからない自分でもなんとなく利用することが出来ました. ありがとうございました.
Web サイトの監視について, 対象のコンテンツ差分をチェックするというアプローチを検討して実装してみました. 意図したコンテンツの変更についても検知してアラートが飛んでくる状況ですが, これはこれで外形監視上の変更履歴として利用出来るのではと考えています.
実装にあたり, 使った技術要素を見てみると, チェックのフレームワークとして Jasmine というテストフレームワーク (と言っていいのかわかりませんが), 実際の基盤としては CircleCI と出来合いのフレームワークを組み合わせることでシュッと仮実装まで持ってくることが出来ました. 技術の進化というものは本当に素晴らしいものですね.
YAMAP に入社して一年が経とうとしていますが, エンジニアとして, 自分なりの「新しい山を作ろう」で頑張っていきたいと思います. これからも宜しくお願い致します.
フルマラソンの練習会的な位置づけで全国各所で開催されているらしい「◯◯ 30K」シリーズの鹿児島開催版である「鹿児島 30K」で 30 キロ走ってきたので振り返りたいと思います.
30km走はマラソンの1カ月前の必須トレーニング。マラソンシーズンで「自己ベスト更新」「初完走」を狙う人にとって本番へ向けた「脚づくり」とシミュレーションにぴったりです!
上記のページに記載されている通り, レースではなく練習会的な位置づけとなるイベントのようです. とは言え, 今年はフルマラソンを一回も走っていない自分にとっては少し距離が短いマラソン大会という位置づけで挑みました. また, 後付となりますが, 雨風のレースに対して激しい苦手意識があったので完走することでその苦手意識を少しでも払拭出来ればと臨みました.
前日からの雨, さらにスタート直前になって強くなる風と雨...棄権したい気持ち一杯でしたが, とりあえずいけるところまで走ろうと思いスタートしました. 目標は 1 キロ 4 分ペース. 30 キロで 2 時間を切れれば最高だと思っていましたが, ひとまずフルマラソン 3 時間切りを目指す人達に用意されたペースランナーの後ろについて一周 3 キロのコースを 4 分 10 秒 /Km 程度でペースを刻みます.
冷たい雨と強い風が体温を奪っていきます. 普通は走れば体が温まりますが, 今回は走っても走っても体は温まらず足先は冷えてしまい接地の感覚すら無い状態で走り続けます. 動かない体を無理やり動かそうとするので呼吸は上がってきて普段のジョッグと比較すると当然ですがキツさを感じました. また, 想定していたよりもアップダウンがあり, 特に 1.5 キロ過ぎの 200m くらいの上り坂は体力を奪い, 乳酸の高まりを感じました.
途中で摂取したのは塩飴 1 個とエナジージェルを 2 つ, 給水地点でのスポーツドリンクと水. 結局, 足が攣ってしまったので 2Run を摂っておくべきだったと反省していますが, 2Run 無しで 20 キロを超える距離を走れたことは小さな自信となりました.
また, 今回のレースでは HOKA ONE ONE の RINCON で走りました.
履いて走った感じをもう少しレポート出来れば良いのですが, 先述の通り足先が冷たく感覚が無い状態でしたので何となくクッションが効いているなーという感覚しかありませんでした. NIKE の ZOOM FLY3 あたりで感じる反発力はあまり感じませんでした. きっとカーボンプレートの有無なのかな.
本来であれば, 後半の 5 周はペースアップしていきたかったところですが, 結局ラスト一周までは体力を温存, ラスト一周をやっと目標としていた 4 分 00 秒/Km で走りきることが出来ました. 今回は 2Run を一回も摂取せずに走ったので案の定, 足はピキピキ攣りまくりながら走りました.
苦手意識のあった雨風の中で完走も出来て 30 キロを 2 時間ちょっとで走ることが出来たことは良かったと思います. また, 最後の一周は 4 分 00 秒/Km くらいまでビルドアップ出来たのは良かったと思います. しかし, フルマラソンを 2 時間 50 分切りを目指している状況からすると, 終盤の体の重さと足攣りは相変わらずで, フルマラソンの場合の残り 12 キロをどう走るのか 2 月の別大までに自分なりの答えを見つけたいと思います.
最後に練習会という位置づけながら一生懸命応援してくれた奥さんや父, 食事面のサポートをしてくれた母, あの過酷な状況でレースをサポートしてくださったスタッフの皆さんには本当に感謝しています. ありがとうございました.
鹿児島 30K で 30 キロ走ってきた. 腹が立つくらいの風雨と寒さで DNS (Did not start 棄権) も考えたけど, 雨が降っている時の苦手意識を払拭したいという思いもあったので出走. 案の定, 雨は冷たいし風は強いしで体は冷えていく一方で接地の感覚もなく完走出来るか不安になりつつもなんとか完走することが出来た.
結果は以下の通り. 目標としていた 4 分ペースで走り切ることは出来なかった (早々に諦めた) けど, 無難にサブスリー圏内で走り切ることが出来た.
結局, 鹿児島のアプライドで中古デスクトップ PC を購入. Core i5 にメモリ 8GB, SSD で予算内におさめることが出来た. 早速, セットアップを行い, 難なく移行が出来たので本当に良かった.
[
キーが何もしていないのに PC 起動時から勝手に入力されるので, ログオンするのにも一苦労HOKA ONE ONE の Carbon X をキャナルシティのゼビオで発見!試し履きしていい感じで一瞬グラついたけど我慢した.
スタッフとして参加した.
YAMAP Night にスタッフ~~~として参加したけど, ユーザーさんの熱量のすごさにスタッフ~~~なのにお酒が進んだ. こんなにもユーザーさんに愛されている会社は初めてでごわす.
— Yohei Kawahara(かっぱ) (@inokara) 2019年12月19日