OpenAPI Generator で Gatling Client を生成してみた
OpenAPI Generator 3.0.0 リリース!!
やったぜ。2.0 はとか野暮なことはなしです。*1
ということでリリースノートを見ていると、New Generators
ところに Gatling の文字があるではないですか。
試すしかない、ってことでやってみました。
やってみた
コマンド
java -jar openapi-generator-cli.jar generate -i "/path/to/input.yaml" -o output -g scala-gatling
-g scala-gatling
で galing 生成を指定しております。
フォルダ構成
├── build.gradle └── src └── gatling ├── resources │ ├── conf │ │ ├── baseline.conf │ │ ├── CD.conf │ │ ├── CI.conf │ │ ├── default.conf │ │ ├── logback.xml │ │ ├── longevity.conf │ │ └── stress.conf │ └── data │ └── null-pathParams.csv └── scala └── org └── openapitools └── client ├── api │ └── DefaultApiSimulation.scala └── model └── Empty.scala
ということで、Gradle のプロジェクトでした。
Android で軽く触ったくらいであんまりですが、まぁなんとかなります。
動かしてみて
食わせた Swagger は認証なしの適当なやつですが、きちんとアクセスしてくれました。
もうちょい確認が必要ですが、初期としては使えそう?
flood でも試してみましょうかねー
企業情報 or アプリ名のところ、test
とかっていれてよいのかしら…?
Rust の CLI ツールで引数の値が特定のものであれば別の引数を必須にしたい
短く
crap.rs の requires_if/requires_ifs を使おう。
.arg( Arg::with_name("iterator-type") .short("t") .long("iterator-type") .possible_values(&IteratorType::variants()) .requires_ifs(&[ ("AT_SEQUENCE_NUMBER", "sequence-number"), ("AFTER_SEQUENCE_NUMBER", "sequence-number"), ("AT_TIMESTAMP", "timestamp"), ]) .default_value("LATEST") .value_name("TYPE") .help("Sets iterator type."), ) .arg( Arg::with_name("sequence-number") .long("sequence-number") .value_name("NUM") .help("Set Sequence number when Iterator Type is AT_SEQUENCE_NUMBER or AFTER_SEQUENCE_NUMBER.") .takes_value(true), ) .arg( Arg::with_name("timestamp") .long("timestamp") .value_name("TIMESTAMP") .help("Set timestamp(UNIX Epoch milliseconds) when Iterator Type is AT_TIMESTAMP.") .takes_value(true), )
k-iter/main.rs at f22bd285818a23ec5eb766d53798a584ddaffed2 · ROki1988/k-iter
背景
AWS Kinesis Stream のイテレータは、下記の通り 5 種類あります。
- LATEST
- AT_SEQUENCE_NUMBER
- AFTER_SEQUENCE_NUMBER
- AT_TIMESTAMP
- TRIM_HORIZON
このうち 3 種には値が必要なので、追加のオプションで指定してもらいたい感じでした。
なので、そのオプションはイテレータが 3 種のうちのどれかであれば必須、となります。
そんなのかけるのやら…
多機能引数パーザ clap
すごいですねー。ありましたよ。requires_ifs
ある引数に対する追加設定として記述できます。
タプルの1つ目が、その引数がとりうる値で、2つ目が必須となるオプションの名前となります。
Arg::with_name("iterator-type") .short("t") .long("iterator-type") .possible_values(&IteratorType::variants()) .requires_ifs(&[ ("AT_SEQUENCE_NUMBER", "sequence-number"), ("AFTER_SEQUENCE_NUMBER", "sequence-number"), ("AT_TIMESTAMP", "timestamp"), ])
先にあげた例を抜粋しました。
今回であれば、iterator-type
に対して、AT_SEQUENCE_NUMBER か AFTER_SEQUENCE_NUMBER、AT_TIMESTAMP の時にそれぞれ必須となる引数の名前を指定してます。
自分で書いてもよいのですが、あるのであれば使います。
ありがたやありがたや。
というわけで
無事 k-iter でオプションを追加できましたー!やったぜ。
これで追跡がらくになる。はず。
次
localstack を使ったテストを書きたい。
Rust でクロスプラットフォーム対応するときに便利だった Cargo Plugin: cross
これ
使い方
cargo install cross
cross build --target i686-unknown-linux-gnu
実際に Travis で動かしている k-iter/.travis.yml at master · ROki1988/k-iter とかを見るとよいかも。
発端
前回 AWS Kinesis Stream をひたすら見るやつを作ったわけですが、バイナリも用意せねば、となりました。
んで、Windows は AppVeyor でサクッとできました。macOS 向けも Travis 上でできました。
でもなぜか、一部の Linux 向けのバイナリができない。
で、調べて cross にいきつきました。
苦悩の跡
めっちゃ頑張った…
Travis CI の設定をパクッt(ry
Travis CI で Linux (x86_64, i686, aarch64) 向け(とついでに macOS 向け)に Rust で書いたツールのバイナリをリリースする - はやくプログラムになりたい
上記のような記事を公開いただいていて、パクれ との記述にありがとうございます!!!と適用してみました。
Build #9 - ROki1988/k-iter - Travis CI がビルド結果になります。
文面に書くと、macOS 向けと x86_64 Linux 向けのビルドに成功し、i686 Linux 向けと AArch64 Linux 向けに失敗しました。なぜだ…
ハッハーン…いつものだな?
OpenSSL を疑いました。
というのも、Rust で OpenSSL を使用する場合、crate が対応しているバージョンがインストールされていないとビルドできなかったり、実行できなかったりするからです。
rust-openssl/build.rs at master · sfackler/rust-openssl を全部見切れていないので事情は定かでないですが、ビルド時にいろいろ見に行っている模様。
ので、
- OpenSSL をインストールしたり
- OpenSSL のバージョン確認したり
- パス確認したり
- OpenSSL のバージョン指定でインストールしようとしたり
- sfackler/rust-openssl: OpenSSL bindings for Rust の環境変数での指定を使ってたり
しましたが、ことごとくダメでした。
ただ最後の環境変数指定でもできなかったときのエラーメッセージをボヤっと見てピンときて、クロス環境向けにビルドされた OpenSSL のがいるのか!と仮説を立てました。
とはいうものの
さすがにクロスのバイナリそれぞれ用意して云々はハードル高いぞ…と、なんかあるやろで見つけたのが cross になります。
上記にて使われているのを発見して、参考にさせていただきました。
結果としてビルドもできて、やったーというところです。
タグ切ったところ、パクってきた拝借してきた設定どおりにきちんと Github に公開されました。
つかってみて
すっごい考えられてるというか、賢くやってはるなーというかんじです。
CLI のコマンドも cargo
から cross
に変えるだけですし、docker 環境がない場合とある場合も同じように動いてくれますし、CI のキャッシュも効きますし。
AWS Lambda の時も感じましたけど、コンテナホント便利ですね。
あとはテストとかにも使いたいんだよなぁ。こう…#[test]
の下とかにアトリビュート書いて実現できると嬉しいかも。
CLI で AWS Kinesis Stream の中身をひたすら追ってくれる k-iter をつくってる
作ったもの
インストール方法
rustup.rs - The Rust toolchain installer
rustup を設定したうえで、下記コマンドを実行。
cargo install --git https://github.com/ROki1988/k-iter.git
もしくは Releases · ROki1988/k-iter より合致するものをダウンロードして展開。
使い方
k-iter -n event-stream -r ap-northeast-1
n
の後にストリーム名を、r
の後にリージョン名を入れればガンガン見てくれます。
今のところはコマンド実行以降に Put されたレコードを見ていくだけです。
動機
AWS Kinesis Stream はいったん投入してしまうと、中になにが入ってるか追うためにコードをかく必要があります。コンソールから見れないから。
Lambda の Blueprint に Kinesis のイベントを処理するぜー、てのもあるのですが、CLI に出したい、という欲がでます。
ですので、秘伝のたれのごとき Python コードを実行して CLI 上で出してました。
だがしかし、迂闊に brew upgrade
を実行した結果、Python の実行環境が再構築の憂き目にあい、こりゃシングルバイナリで動くやつ作らにゃきつい、となった次第です。
Rust 製なのは趣味です。
やってみたいこと/考えてること/もらえた意見
- 実行バイナリはよ
- Verbose モードとかほしい。Put された時間とかパーティションキーとか
- Iterator Type 対応したい。
TRIM_HORIZON
とか。- オプションに依存関係が出てくるので、ちょいと厄介
clap-rs の修行が必要そう
- オプションに依存関係が出てくるので、ちょいと厄介
--exec
とか作ってデータに処理かけたいjq
かけたりするイメージ。やりたくない?
- UTF-8 文字列決め打ちで出力してるけど、バイナリ表示の需要もありそう?
- Big とか Little の切り替えもいるのだろうか。
--print-format=string|byte-be|byte-le
てな感じ
- Big とか Little の切り替えもいるのだろうか。
- Shard 複数を同時に
- できっかなぁ…
Rust で Scala の continually ぽいもの
こんな感じ?
extern crate rand; use rand::{Rng, thread_rng}; use std::usize; pub struct Iterate<A> { func: A } impl<B, A> Iterator for Iterate<A> where A: FnMut() -> B { type Item = B; #[inline] fn next(&mut self) -> Option<B> { Some((self.func)()) } #[inline] fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) } } fn continually <A, B>(f: A) -> Iterate<A> where A: FnMut() -> B { Iterate { func: f } } fn main() { let mut rng = thread_rng(); let a = std::iter::repeat(1).into_iter().map(|_| rng.gen::<u32>() % 100u32).take_while(|x| *x != 0u32).collect::<Vec<u32>>(); let i = continually(|| rng.gen::<u32>() % 100u32).take_while(|x| x != &0u32).collect::<Vec<u32>>(); println!("{:?}", a); println!("{:?}", i); }
きっかけ
Iterator.continually はそういうことかー、と納得してる
— 萬屋 rohki (@r_ohki) 2018年4月12日
Scala の continually をみて、なるほど都度評価してくれるのか、と納得して、はて Rust では、となった次第。
書いてみて
std::iter::repeat
もあるにはあるのですが、Clone
trait を実装している必要があって、FnMut
を渡せませんでした。たぶん。
ので、軽く書いてみたら動きました。でもありそう。見つけられてないだけで。
あと、表面だけまねてるので、いろいろ考えが足りてなさそうでもあります。
でも動いたから満足。
Elasticsearch のクエリを知るのに elastic4s がよかった
Elasticsearch はややこしい
ややこしいというか難しいというか、面倒くさいというか…
で考えたところ、そも JSON を組み立てるのがそこそこ以上にしんどいんですよね。末尾の ,
とか。
Kibana も補完はあるのですが、そのあたりが面倒くさくて、なんか学ぶのが億劫になっておりました。
で、表題の話。elastic4s です。
sksamuel/elastic4s: Elasticsearch Scala Client - Non Blocking, Type Safe, HTTP, REST API, TCP
Scala で Elasticsearch を扱うためのライブラリになってます。
かなーり頑張っていて、検索結果を safeTo で変換できたりとか、ややこしい aggs
に型の誘導があったりします。
あと 6.0 以上であれば AWS Elasticsearch Service の IAM 認証付きリクエストも行けます。AWS_DEFAULT_REGION
を環境変数にいれなきゃですが。
Aggregations がすごい
いやーえぐい。ほんとえぐい。というかこれだけの量をよく定義しはりました。
val resp = http.execute { search("childrenaggs").matchAllQuery().aggs( dateHistogramAgg("agg1", "date").interval(DateHistogramInterval.Month).addSubagg( childrenAggregation("agg2", "answer").addSubagg( termsAgg("agg3", "text").size(1) ) ) ) }.await.result val september = resp.aggs.dateHistogram("agg1").buckets.find(_.date == "01/09/2017").get val sept_answers = september.children("agg2") sept_answers.docCount shouldBe 3 sept_answers.terms("agg3").buckets.head.key shouldBe "god"
テストコード から抜粋したのが上記です。
入れ子の入れ子の入れ子、になってるのかな? もはやわからんわけですが、型に沿って書けるのでよかったです。
んで、aggs
で返ってくる結果のキー名とか方とかも決まってるので、これもとれます。
テスト支援のモジュールもある
まだきちんと試せてないですが、テスト用のモジュールもあります。
Docker を起動するタイプとか、組み込みタイプとか。至れり尽くせり。
サンプルもあって試せる
elastic4s/samples at 151fea1fb680bed793bd3c89149b266bcb9c6129 · sksamuel/elastic4s
丁寧なことに Maven やら Sbt のサンプルプロジェクトも用意されてるので、結構手軽にためせます。
ここでクエリを書いて、.show
で文字列にして確認してを繰り返して、理解が深まった感じです。
与太話
ElasticDsl.scala ってファイルを見ながら、確かに技術ドメインであってもドメインであって、表現してくれてる言語があれば理解が深まる、ってことなのかなー、ORM とかもそういう役割あるのかなー、などと思考が飛躍しておりました。
与太話おわり!elastic4s よいすよ!!
Scala で Array 等を制限に合わせて分割する
短く
grouped(size)
を使いましょう
背景
Scala で AWS Kinesis へ PutRecords しようとしたときに、上限に引っ掛かりました。
で今回抵触した上限というのが、PutRecords 1 回あたりに含められるレコード数で、500 までとのこと。*1
なので 500 毎に分割して PutRecords したいわけだけど、分割…あるはずだよなーと探して見つかりました。
方法
(1 to 10000) .grouped(500) // これ .foreach(put)
たったこれだけです。
ただまぁ自前で作ると脳みその裏側でいろいろ考えたりするわけですよ。
そも動くようにするところから始まり、速度とか、オブジェクト生成の回数とか、いろんな Collections への対応とか。
あるなら使うがベストです。こんなの絶対にあるはずですし
おわりに
名前がよくない!(理不尽)
splitAt
は違うしなぁとかで引っかかってました。
sliding
まで行きついてコード書いた後に、あれよく見たら grouped
あるやん、でやっとこさ到達しました。
Rust では chunk
で、そうか chunk
というワードがあったか、という感じ。検索のための語彙が増えました。