selmertsxの素振り日記

ひたすら日々の素振り内容を書き続けるだけの日記

webpackをupdateしたらterserの問題でbuildができなくなる問題の対処法

TL;DR

  • webpackのバージョンを v4.29.0 にupdateしたらbuildできなくなった
  • どうやら最新の terser-js に問題があったらしい
  • terser-js3.14 にしたら問題が解決した

事象

  • npm update をして webpackのバージョンを v4.29.0 にした
  • その状態で webpack --mode production をしたら下記のエラー
ERROR in index.js from Terser
TypeError: Cannot read property 'minify' of undefined
    at minify (xxx/node_modules/terser-webpack-plugin/dist/minify.js:175:23)
    at module.exports (xxx/node_modules/terser-webpack-plugin/dist/worker.js:13:40)
    at handle (xxx/node_modules/worker-farm/lib/child/index.js:44:8)
    at process.<anonymous> (xxx/node_modules/worker-farm/lib/child/index.js:51:3)
    at emitTwo (events.js:126:13)
    at process.emit (events.js:214:7)
    at emit (internal/child_process.js:772:12)
    at _combinedTickCallback (internal/process/next_tick.js:141:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
  • terser-webpack-plugin が怪しいらしかったので、そのリポジトリを追っていくとこちらのissueを発見。
  • npm i terser@3.14 してからbuildしなおしたら問題なく動いた

【GCP】Datastoreを作ってしまったGCPプロジェクトではFirestoreを使えない

表題の通り。それだけなんだけれども、同じ悲劇を経験する人がいないようにブログに書きました。

2019年1月、Firestoreが東京リージョンでも使えるようになった。 https://firebase.google.com/docs/firestore/locations?hl=en#location-r

せっかくなので、今作っているcloud functionsのデータベースをDatastoreではなくてFirestoreで構築しようと考えた。( FirestoreはDatastoreの上位互換であり、Datastoreで使える機能はFirestoreでも利用可能 )

ということでドキュメントを見ながらコードを書いて、動作確認をしようとしたら下記のエラー。

{ Error: 9 FAILED_PRECONDITION: This project contains a Cloud Datastore database and does not support Cloud Firestore API calls.
    at Object.exports.createStatusError (/Users/shuhei.morioka/project/speee/datadog_slack_report/node_modules/grpc/src/common.js:91:15)
    at Object.onReceiveStatus (/Users/shuhei.morioka/project/speee/datadog_slack_report/node_modules/grpc/src/client_interceptors.js:1204:28)
    at InterceptingListener._callNext (/Users/shuhei.morioka/project/speee/datadog_slack_report/node_modules/grpc/src/client_interceptors.js:568:42)
    at InterceptingListener.onReceiveStatus (/Users/shuhei.morioka/project/speee/datadog_slack_report/node_modules/grpc/src/client_interceptors.js:618:8)
    at callback (/Users/shuhei.morioka/project/speee/datadog_slack_report/node_modules/grpc/src/client_interceptors.js:845:24)
  code: 9,
  metadata: Metadata { _internal_repr: {} },
  details: 'This project contains a Cloud Datastore database and does not support Cloud Firestore API calls.' }

ここで1~2時間くらい原因を調査したが分からず、issue trackerを見てみたらこんな文言が。

If you absolutely want to use Firestore proper, you need to open a new project and deploy your app to the new project, where you choose Firestore from the start.

https://issuetracker.google.com/issues/113075718

ということで、Datastoreをすでに使っているプロジェクトではFirestoreは使うことが出来ません。これから触る人は、誤って使わないように気をつけましょう〜

ちなみに

Cloud Firestore への自動アップグレード  |  Cloud Datastore ドキュメント  |  Google Cloud

Cloud Firestore の一般公開後、ある程度の時間を置いてから既存の Cloud Datastore データベースの所有者に連絡し、Cloud Firestore の Datastore モードへの自動アップグレードのタイミングを相談させていただく予定です。

ということです!

「U30のための最速キャリア戦略」の所感

読んだもの

speakerdeck.com

読んでみた経緯

ここで紹介されていたスライドの内容があまりにも納得がありすぎたので、全部読んでみたくなった。

気になったポイント

  • 職位が上がるにつれて、コードの外側の設計スキルの能力が求められる
  • 正しく意見をぶつける
    • 意思決定者を理解する
    • 正しい目標が何かを考え、適切に意思決定者に伝え、意思決定に反映していく
    • そのためには、適切に状況(KPIや日常の会話から)を把握し、
    • 現在の課題に対して説得力のある解釈を用意し
  • 意にそぐわなくとも、組織の意思決定内容に貢献する
    • 意思決定の場、議論、準備に全力を注ぐ
    • 意思決定が意にそぐわないのは、自分の意思表明の方法に問題がある
    • 人生において全力で取り込めるプロダクトの数はそう多くない
    • 少なくとも、全力で取り組めば自分の経験になる

所感

職位が上がるにつれて、コードの外側の設計スキルの能力が求められる というのは最近常に感じる。プロジェクトの成否が、純粋に技術の問題だけに終始するという幸せな状況はほとんど見たことがない。技術力は、実現の可否判断や実現速度を大幅に上げてくれる要素ではあるものの、プロジェクトが正しい方向に向かっていることを担保してくれはしない。正しい方向性を目指すこと、軌道を正しい方向に修正するには技術以外の知見が必要であると感じるシーンに、ここ数年で何度も出くわしてきた。それはプロジェクトマネジメントの視点であったり、または市場理解、データ理解であったりした。

その中においてどのように振る舞っていくかの一つの示唆が、このスライドには多く含まれていた。松本さんのように真正面から全力でぶつかっても良いだろうし、仲間を信じて自分の専門スキルを研ぎ澄ましても良いだろう。

人生において全力で取り込めるプロダクトの数はそう多くない。自分がどのようなスキルセットを持って、課題に取り込んでいくのか。そしてその経験を糧にしていくのか考えされられる資料だった。

GCPでCloud Functionsを作る際の個人的なTIPS

この記事は技術同人誌Advent Calendar 2018の19日目の記事です。 こんにちは。 @selmertsxです。主にRailsのサーバーサイドエンジニアをやってます。

技術同人誌 Advent Calendarということで、今年の11月にNextPublishing様から出版させて頂いたAmazon Web Servicesサーバーレスレシピ という本に書ききれなかった、「Serverlessでチャットボットを作る」というお話を、僕が以前作った serverless-prpolice というslack botを題材にお話をさせていただこうと思っていました。

しかしながら、最近の業務ではGCP(Google Cloud Platform) のCloud Functionsを利用していることが多く、そちらのキャッチアップをしたいなぁという気持ちになりました。そこで、最近作った Cloud Functions製のslack botである datadog_slack_report を題材にして、僕がCloud Functionsを作る際によくやるTipsなどを説明させて頂きます。

前提条件

  • Datadog Slack Report は TypeScriptで書かれています
  • Cloud FunctionsはServerless Frameworkなどを利用せず、素のgcloud コマンドを利用してデプロイされています
  • TypeScriptのコードはwebpackを利用してバンドルされています
  • 監視したいEC2インスタンスには productタグにプロダクト名をつけてもらう必要があります (ex: product: sample )
  • cloud schedulerの設定等、細かい部分についてはここでは説明しません
  • 開発には Visual Studio Code を利用しています
  • testにはjestを利用しています

※ ここで説明していない細かい諸々に関して、コメントを頂ければ説明を追加しようと思います!

Datadog Slack Report とは何をするものなのか

f:id:selmertsx:20181218191749j:plain
datadog slack reportのイメージ

毎日決まった時間に、Datadogを利用している監視ホスト数をproduct毎にまとめてslackで通知します。

Datadog Slack Report をなぜ作ったのか

ぼくがいる会社ではDatadogを利用して全てのサービスのホストを監視しています。僕たちの会社ではDatadogのサービスを1つのアカウントで運用しています。Datadogではアカウントに親子関係を作ることが出来るので、1つの会社で複数のサービスを監視する際は、支払い用のアカウントと各サービスごとのアカウントを分けるのが一般的な利用方法でしょう。しかしながらその方法では、アカウント間でサーバーメトリクスや、プロダクト毎のモニタリング方法、アラート設定等々を、簡単に共有したり確認したりすることができません。 ( 今は違うようでしたら教えて頂けるとめっちゃ喜びます!!!! )

なので僕たちの会社では、1つのアカウントで複数のサービスの監視をすることにしました。プロダクト毎の按分の計算については僕が温かみのある手計算をしいます。 これはさすがに自動化したいなぁと思い、Cloud Functionsのキャッチアップがてら作ってみました。

TIPS

jest & ts-nodeとdebuggerを利用して開発する

AWS Lambdaや Cloud Functionsをいきなり書き始めると確認がとても大変です。なので僕は普通にTypeScriptで動くコードを書いて、一通りできあがった後にLambdaやCloud Functionsに合わせてコードをラッピングしていきます。mockするのが容易な処理であれば、テストコードから書きだすこともあります。Visual Studio Code をEditorとして利用している場合、簡単にdebuggerを使って開発することができます。

f:id:selmertsx:20181218202639p:plain

debuggerを使うときの設定は下記のようになります。

// https://github.com/selmertsx/datadog_slack_report/blob/master/.vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Jest",
      "preLaunchTask": "build",
      "program": "${workspaceRoot}/node_modules/jest/bin/jest.js",
      "args": [
        "${file}",
        // 現在のプロセスで逐次テストを実行していく設定.
        // この設定をしないと複数のchildプロセスでテストを実行するらしい
        // debuggingのために有用とのことだったので、この設定を有効にした
        // https://facebook.github.io/jest/docs/en/cli.html#runinband
        "--runInBand",
        // debugの際はcacheを無効にした。
        // cacheを無効にすると、2倍くらい遅くなるらしい。
        "--no-cache"
      ],
      "cwd": "${workspaceRoot}",
      "console": "integratedTerminal"
    },
    {
      "name": "ts-node[debug]",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js",
      "args": [ "${relativeFile}" ],
      "console": "integratedTerminal"
    }
  ]
}
// 動作確認の際に利用するコード
// https://github.com/selmertsx/datadog_slack_report/commit/f26a441d23d80f4f9b06541240c5fe20bff8231d

async function datadog_handler(): Promise<void> {
  const fromTime = moment({ hour: 0, minute: 0, second: 0 })
    .add("days", -1)
    .format("X");
  const toTime = moment({ hour: 23, minute: 59, second: 59 }).format("X");

  for (const product of products) {
    const productMetrics: ProductMetrics = await datadogClient.countHosts(
      product,
      fromTime,
      toTime
    );
    attachments.push(SlackMessage.attachments(productMetrics));
  }
  await slackClient.post(attachments);
}

datadog_handler(); // ここで実行される。Lambda化するときなどは、この行を取り除き、引数を適切に設定する

sourcemapを埋め込む

f:id:selmertsx:20181218210015p:plain

TypeScript & webpack環境でCloud Functionsを利用する場合、エラーログは上記の図のように丸め込まれてしまい、ほとんど読むことができません。 なのでsource-map-supportというモジュールを利用して、エラーログを詳細に見れるようにします。

設定方法

npm install source-map-support
// src/index.ts
// この一行を追加
import "source-map-support/register";
// webpack.config.js
module.exports = {
  ...
  devtool: 'source-map', //<= これを追加
  ...
}

結果

f:id:selmertsx:20181218205442p:plain

このように設定すると下記の図のように、エラーが発生している箇所の詳細を把握できるようになります。webpackを利用している際は必ず入れた方が良いモジュールですね。

Cloud FunctionsをLocalで実行する

debuggerをいい感じに利用できていると、正直なところCloud FunctionsをLocalで実行するメリットがあまりないのですが、一応載せておきます。

設定方法

npm i -D @google-cloud/functions-emulator
$ npx functions start
Starting Google Cloud Functions Emulator...
Google Cloud Functions Emulator STARTED
┌────────┬───────────┬─────────┬─────────────────────────────────────────────────────────────┐
│ Status │ Name      │ Trigger │ Resource                                                    │
├────────┼───────────┼─────────┼─────────────────────────────────────────────────────────────┤
│ READY  │ subscribe │ HTTP    │ http://localhost:8010/xxx/us-central1/subscribe │
└────────┴───────────┴─────────┴─────────────────────────────────────────────────────────────┘
$ npx functions deploy datadog_handler --trigger-topic=datadog_report
Copying file:///var/folders/64/xxx/T/tmp-3550rM1YUf87egAJ.zip...
Waiting for operation to finish...done.
Deploying function......done.
Function datadog_handler deployed.
┌────────────┬──────────────────────────────────────────────────────────────────────────────────┐
│ Property   │ Value                                                                            │
├────────────┼──────────────────────────────────────────────────────────────────────────────────┤
│ Name       │ datadog_handler                                                                  │
├────────────┼──────────────────────────────────────────────────────────────────────────────────┤
│ Trigger    │ google.pubsub.topic.publish                                                      │
├────────────┼──────────────────────────────────────────────────────────────────────────────────┤
│ Resource   │ datadog_report                                                                   │
├────────────┼──────────────────────────────────────────────────────────────────────────────────┤
│ Timeout    │ 60 seconds                                                                       │
├────────────┼──────────────────────────────────────────────────────────────────────────────────┤
│ Local path │ /Users/shuhei.morioka/project/xxx/datadog_slack_report                         │
├────────────┼──────────────────────────────────────────────────────────────────────────────────┤
│ Archive    │ file:///var/folders/64/xxx/T/tmp-3550rM1YUf87egAJ.zip │
└────────────┴──────────────────────────────────────────────────────────────────────────────────┘

結果

$ npx functions call datadog_handler
ExecutionId: 790ca715-a537-4f3a-8657-0301e71c8a36

所感と今後の予定

以上、一通り Cloud Functionsを利用してみました。 定性的なお話になってしまいますが、AWS Lambda よりも簡単に開発できる反面、API Gatewayなどのようなツールがないので Functionの実行できるユーザーを制限できない (アルファ版として一部ユーザーには提供されているっぽい) など、AWSの方がServerless の権限まわりに関しては一歩先に進んでいるなぁという印象を受けました。

今後 datadog slack reportについては、下記の機能を追加していく予定です。

  • プロダクト毎のホスト料金按分計算機能
  • プロダクト毎の監視台数設定機能
  • プロダクト毎のAPMの料金按分計算機能
  • プロダクト毎のAPMの監視台数設定機能

監視台数設定機能周りについては、firebaseと認証周りをキャッチアップするために、SPAでサービスをつくっていければな〜と思っています。 その他要望などなどありましたら、GitHubのissueかこのブログへのコメントで頂けると幸いです〜。

TypeScript開発における僕のVisual Studio Code設定

僕が Visual Studio Code を利用して開発しているときの設定。 こうすると ts-nodeとjestの双方でdebuggerを利用できる。

※ 他に良い方法があれば :pray:

設定ファイル

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Jest",
      "preLaunchTask": "build",
      "program": "${workspaceRoot}/node_modules/jest/bin/jest.js",
      "args": [
        "${file}",
        // 現在のプロセスで逐次テストを実行していく設定.
        // この設定をしないと複数のchildプロセスでテストを実行するらしい
        // debuggingのために有用とのことだったので、この設定を有効にした
        // https://facebook.github.io/jest/docs/en/cli.html#runinband
        // debugの際はcacheを無効にした。
        // cacheを無効にすると、2倍くらい遅くなるらしい。
        "--runInBand",
        "--no-cache"
      ],
      "cwd": "${workspaceRoot}",
      "console": "integratedTerminal"
    },
    {
      "name": "ts-node[debug]",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js",
      "args": [ "${relativeFile}" ],
      "console": "integratedTerminal"
    }
  ]
}
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build",
      "type": "shell",
      "command": "npx tsc"
    }
  ]
}