サカナ未遂

プログラミング、筋トレ、子育て

JavaScriptのawait式をAsync Functionの中で使用するときの注意点

JavaScriptのPromiseとかawaitとか雰囲気で乗り切ってきたけど、ちゃんと腰据えて勉強しようと思って購入したJavaScript Primer

非常に分厚いけど、読みやすくサンプルコードも豊富なので理解しやすかった。 まだまだ全部よめてないけど、非同期処理のところを集中的に読む。

第22章で気をつけないとと思った箇所

async function asyncMain(){
  await new Promise((resolve) => {
    setTimeout(resolve, 16); 
  });
};

console.log("1. asyncMain 関数を呼び出します");
asyncMain().then(() => {
  console.log("3. asyncMain関数が終了しました。");
});
console.log("2. asyncMain 関数外では次の行が同期的に呼び出される");

このコードを実行した場合、asyncMainでawaitをつかって処理をとめているけど、関数を呼び出してるメインの処理はとまらず最後のconsole.logを出力する。 あくまで関数の中ではとまっているだけである。 awaitで何でも止めれると思っていたので知ることができてよかった。

CloudRunを使ってみた

GCPのCloudRunというサービスを使うことがあったので簡単な使い方をメモっときます。

CloudRunとは

公式URLより https://cloud.google.com/run?hl=ja

コンテナ化されたアプリケーションをすばやく安全にデプロイ、スケーリングできる、フルマネージド型のコンピューティング プラットフォーム

とあります。 コンテナに入れたwebアプリを、そのままデプロイできるってことですね。 GCPのContainerRegistoryにコンテナをpushし、CloudRunでデプロイするだけで動かせます。

CloudRunの料金

https://cloud.google.com/run/pricing?hl=ja f:id:tera_chan3700:20200618212128p:plain

ちょっと試すくらいならほぼ無料で使えます。

あとContainerRegistoryの料金がかかりますが、これも微々たるものです。 https://cloud.google.com/container-registry/pricing?hl=ja 個人で試すには懐が痛まなくて好きそうです。

注意

CloudRunからCloudRun、または他のサーバレスを無限ループで呼ぶような処理があると危険です。そこは個人で気をつけてください。 例:https://blog.mmmcorp.co.jp/blog/2019/12/25/lambda-cloud-bankruptcy/ これはAWSですが、GCPでも起こりえます。

サンプル

GOで簡単なエコーサーバーを作ります

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
)

func handler(w http.ResponseWriter, r *http.Request) {
    dump, err := httputil.DumpRequest(r, true)
    if err != nil {
        http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
        return
    }
    fmt.Println(string(dump))
    fmt.Fprintf(w, "<html><body>hello Cloud Run!!!</body></html>")
}

func main() {
    var httpServer http.Server
    http.HandleFunc("/", handler)
    log.Println("start http listening :8080")
    httpServer.Addr = ":8080"

    log.Println(httpServer.ListenAndServe())
}

8080ポートにアクセスすると、「hello Cloud Run!!!」の文字列を返すサーバーです。 実行して確認します。

$ go run main.go
2020/06/18 20:01:04 start http listening :8080

サーバーが起動したのでアクセスしてみる f:id:tera_chan3700:20200618213242p:plain

レスポンスが帰ってきました。

次にこれをビルドして実行するDockerfileを作ります。

FROM golang:latest

#ディレクトリ作成
WORKDIR /go/src/go-image
#ホストOSのmain.goをWORKDIRにコピー
COPY main.go .

#バイナリを生成
RUN go install -v .

#バイナリを実行
CMD ["go-image"]

これをビルドします。

$ docker build -t gcr.io/<自分のプロジェクトID>/cloudrun-test:v1 .

ローカルで実行してみます

$ d run -p 8080:8080  gcr.io/<自分のプロジェクトID>/cloudrun-test:v1

アクセスします。 f:id:tera_chan3700:20200618213636p:plain 動きました。ちゃんとコンテナの中で起動することが確認できました。

コンテナレジストリへのpush

今回はステージングをかります。 gcloudコマンドで事前にログインしています。

GCPにpushする。

docker push gcr.io/<自分のプロジェクトID>/cloudrun-test:v1

入ったことを確認 f:id:tera_chan3700:20200618213808p:plain

CloudRunへのデプロイと実行

サービスを作成をクリック f:id:tera_chan3700:20200618213957p:plain

適当に入力して「次へ」をクリック f:id:tera_chan3700:20200618214119p:plain

さっきpushしたイメージを選択して作成ボタンをクリック f:id:tera_chan3700:20200618214315p:plain

しばらくするとデプロイが完了し、エンドポイントが作成されます。 f:id:tera_chan3700:20200618214521p:plain

ここにアクセスします。 f:id:tera_chan3700:20200618214609p:plain

動きました。 ローカルで作ったコンテナが簡単にデプロイでき、動かすことができます。 タイムアウトなど制限もありますが、ローカルで動いてるコンテナを簡単にデプロイできるのは便利です。

gRPCについて学んだこと

会社の業務でgRPC触ることがあったのですが、そもそもRPCってなんぞやって状態でしたので、勉強してみることにしました。

まずgRPCを勉強しようと思った時に、不明な用語があったのでそれらを整理してから進めることにしました。  

RPCとは

まずRPCは、Remote Procedure Call(遠隔手続き呼び出し)の略で、プログラムから別のアドレス空間にあるサブルーチンや手続きを実行することを可能にする技術のこと。

でgRPCは、Google社内で使われていたRPCフレームワークOSS化され、gRPCと名前がついたもののことだそうです。 ちなみにgRPCのgはGoogleのgではないです。バージョン毎にいろいろg縛りの言葉がついてるようです。 ここに書いてた GRPC Core: g_stands_for

Protocol Buffersとは

gRPCはデータをProtocol Buffersにシリアライズしてやりとりを行う。 Protocol BuffersもGoogleが開発したフォーマットで、XMLとの比較で、3〜10倍小さく、20〜100倍高速であると主張しているとのこと。

ProtocolBuffersは、protoファイルを作成します。 ファイルをコンパイルすると任意の言語用のコードを自動で作成してくれます。 GoやRubyなど様々な言語に対応しています。 現在はproto3です(いつから3なのか、2との違いは何なのかちゃんと調べてない)

試してみる

公式のチュートリアルの通りにやってみる。 まずサンプルをダウンロードし、ディレクトリ移動

$ git clone -b v1.28.1 https://github.com/grpc/grpc
$ cd grpc
$ cd examples/ruby

サーバーを起動する。

$ ruby greeter_server.rb

別のターミナルでクライアントを起動

$ ruby greeter_client.rb
# 結果が帰ってくる
"Greeting: Hello world"

どういう仕組みかコードを確認。

まずgreeter_client.rb

# GreeterServer is simple server that implements the Helloworld Greeter server.
class GreeterServer < Helloworld::Greeter::Service
  # say_hello implements the SayHello rpc method.
  def say_hello(hello_req, _unused_call)
    Helloworld::HelloReply.new(message: "Hello #{hello_req.name}")
  end
end

# main starts an RpcServer that receives requests to GreeterServer at the sample
# server port.
def main
  s = GRPC::RpcServer.new
  s.add_http2_port('0.0.0.0:50051', :this_port_is_insecure)
  s.handle(GreeterServer)
  # Runs the server with SIGHUP, SIGINT and SIGQUIT signal handlers to 
  #   gracefully shutdown.
  # User could also choose to run server via call to run_till_terminated
  s.run_till_terminated_or_interrupted([1, 'int', 'SIGQUIT'])
end

mainでRPCサーバーを0.0.0.0:50051で起動しハンドラーにGreeterServerを設定している。 GreeterServersay_helloというメソッドを持ち、 Helloworld::HelloReply.new(message: "Hello #{hello_req.name}")(これはhelloworld_services_pb.rbに定義されていた。) を実行する。 Hello + リクエストのnameプロパティの値を返す

クライアント側

def main
  stub = Helloworld::Greeter::Stub.new('localhost:50051', :this_channel_is_insecure)
  user = ARGV.size > 0 ?  ARGV[0] : 'world'
  message = stub.say_hello(Helloworld::HelloRequest.new(name: user)).message
  p "Greeting: #{message}"
end

gRPCのスタブを生成し、say_helloメソッドに"world"を渡す。 サーバから帰ってきたメッセージにGreetingを付加して出力している。

所感

まずはこんな感じってのがわかった。 クライアントからサーバーのメソッドを呼び出すという概要は理解できた。 チュートリアルの最初の最初をやっただけなので、protoファイルの作り方やストリーミング など、もっと学習していこうと思います。

参考にさせていただいた資料

booth.pm

grpc.io

k8sで複数環境を触るときに便利なツール

kubernetesで操作する環境が増えてくると、想定外の環境にデプロイするような事故が増えてくるので、少しでも事故を減らすためのツールを紹介します。

kubectx

コンテキストを簡単に切り替えてくれるツール

インストール

$ brew install kubectx

コンテキスト切り替え

# 特定の環境に切り替え
$ kubectx gke_my-project-development_asia-northeast1-a_sample-cluster

、、、、コンテキストが長い…

別名をつけることができる。

$ kubectx MYDEV=gke_my-project-development_asia-northeast1-a_sample-cluster

これで、別名で切り替えることができる。

# 開発環境に切り替え
$ kubectx MYDEV
# 本番に切り替え(本番の別名をつけておく)
$ kubectx PROD

kube-ps1

実行中のコンテキストをプロンプトに表示させることができる。 https://github.com/jonmosco/kube-ps1

インストール

$ brew install kube-ps1

.bashrcの設定

# .bashrc
PS1='\u:\W\$'   # プロンプト表示を、ユーザ名とカレントディレクトリのみにしている(ここは各自の好みで)
source "/<インストールパス>/kube-ps1/share/kube-ps1.sh"
PS1='$(kube_ps1)'$PS1
kubeoff      # デフォルトでオフにしておく
# 表示
$ kubeon

# 非表示
$ kubeoff

こんな感じで表示される

$ kubeon
# ステージングに切り替え
$ kubectx STAGE
(⎈ |STAGE:default)username:workspace$

# 本番に切り替え
$ kubectx PROD
(⎈ |PROD:default)jusername:workspace$

$ kubeoff
username:workspace$

これで自分が操作中のコンテキストを確認しながら作業できるので、少しは安全になります。

転職して約半年が経ちました

5月も終わりになってきて、転職して約半年が経ちます。

 

当初の目標としては、業務以外でももっとたくさんコードを書いてるつもりだっんですが、思った以上に知らないことが多すぎて、そのキャッチアップに追われ、なんとも自身を無くしています。

 

特にインフラ周りの知識がほとんどなく、Docker、k8sGCP、terraformなどのツールやサービスの情報収集に終われ、自身の英語力のなさから来る公式リファレンスを読む遅さと相まって、思った以上に捗らず仕事に追われています。

 

またプライベートでも、妻がフルタイムで働き始めたことによる家事の増加、娘が小学校に入学したことで、出発の時間がこれまでより遅くなり、その分出社が遅れ、退社時間がずれるなど色々ドタバタしていて、仕事以外でなかなかスキルアップの時間が取れない日々が続きました。

 

その対処として、食器洗浄器と、衣類乾燥機を買うことで家事にかかる時間の削減を行いました。

特に衣類乾燥機は、洗濯の後の、「干す」、「取り込む」の二つのプロセスをなくすことができるので(完全には無理ですが)相当の時間短縮になります。

食器洗浄器は、洗う量に対して洗ってる時間が長いので、手で洗った方がいいかと思ったりしますが、洗い終わった後の疲労感がなくなるので、とりあえず毎回使っています。

そんなこんなで、一日1時間半は自分の時間が作れそうなので、まあ焦らず地道にスキルアップしていこうと思います。

 

RubyKaigi2019に参加してきました。

久々にブログを書きます。

タイトルの通り、RubyKaigi2019に参加してきました。 4/18〜20で福岡で開催で、特に一緒にいく同僚もいないので一人ぼっちで行ってきました。

去年Rubyを始めたので、RubyKaigiがどういうものか全然知りませんでした。 あまり詳しくないのですが、相当レベルが高く、自分が行ってもどうなんだろうと思っていました。 去年の末くらいにチケットが発売された後も、行こうか迷っていたのですが、去年末の品川で開催された「Ruby Business Users Conference 2018 Winter」でRuby開発者のMatz(まつもとゆきひろ)さんとお話する機会があり、Ruby会議は楽しいし、初心者でも大丈夫と言っていたので、参加することに決めました。
実際Ruby歴1年ちょっとでは、セッションの内容は高度で、さらに国外のエンジニアの英語スピーチは理解が追いつきませんでしたが、Rubyコミッターの方々の、もっとRubyをよくしていこうという熱い思いは感じ取ることができました。 ぼっちで参加しましたが、東京で顔見知りの方々にアフターパーティで混ぜてもらったり、なんだかんだで楽しく過ごすことができました。 来年は長野県の松本ということで、また絶対に行きたいと思います。

転職後の勉強について

新しい会社に入社し、もうすぐ1ヶ月が経ちます。

まだ不慣れなこともあり、毎日2時間近く残業しているので、業務中以外のインプットもアウトプットも転職後にかなり滞っています。

 

今年は、RubyRailsももっと深く理解したいと思っているし、AWSGCP、DockerやK8sなどインフラ周りの勉強を進めようと思っていたのですが、なかなか時間が取れない状態となっています。

 

ただ自習の時間が取れなくても、業務でDockerやGoogleCloud周りを結構こねくり回したのでかなり理解が進みました。

自習では、ある程度わからないことがあると理解しないまま進んだり、別のことやったりと逃げることもできましたが、業務だと逃げる訳にも行かないので、必死にドキュメントを読み、手を動かし試行錯誤を繰り返して、なんとか業務を進めて行きました。

この後は、テストコードの整備とRuboCopの導入タスクを一人で行なっていくので、この辺りのスキルも業務中に身に着けることができると思っています。

仕事しているだけで、勉強している様なものなので、業務に慣れるまで、自習時間が取れなくても仕方がないと割り切る様にしています。

 

この先は会社がリモートワークを導入するとのことなので、通勤時間がなくなった分、自習に当てられるので、業務+自習で去年以上のスピードで成長できそうな感じがしています。

(去年までは業務で使う技術が古すぎて勉強にならなかった、、、)

 

身につけたDockerとかCloudBuildの知識も、ブログにアウトプットして行きたいなと思っているので、時間が取れたらまとめて公開します。