Shogo's Blog

Nov 11, 2024 - 4 minute read - mysql

LEFT JOINとFOR UPDATEを同時に使うのはやめよう

LEFT JOIN を何度も繰り返し、さらに FOR UPDATE しているMySQLのクエリーを見かけました。 毎回似たようなコメントをするのも面倒なので、そのようなクエリーの問題点をまとめておきます。 たとえばこんな感じのクエリーです。 SELECT * FROM `user` LEFT JOIN `user_prefecture` USING (`user_id`) LEFT JOIN `prefecture` USING (`prefecture_id`) WHERE `user`.`user_id` = 1 FOR UPDATE; TL;DR 以下の理由から、LEFT JOINとFOR UPDATEを同時に使うのはやめたほうがよい。 そもそもロックの範囲を間違えている可能性が高い デッドロックの危険性が高まる ギャップロックの可能性がある FOR UPDATE はロックの獲得のみに使用し、関連する情報を取得するのは別クエリーに分けよう。 LEFT JOINとFOR UPDATEを同時に使うのはやめよう 検証用に簡単なテーブルを作ってみます。 ユーザーは自分の居住地(都道府県)を設定できます。 自分の居住地を明かしたくないユーザーは、居住地を設定を省略することも可能です。 このような要件をもとに以下のようなテーブルを定義してみました。 -- ユーザー CREATE TABLE `user` ( `user_id` BIGINT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(191) ); -- 都道府県のマスターデータ CREATE TABLE `prefecture` ( `prefecture_id` INTEGER PRIMARY KEY, `name` VARCHAR(191) ); -- ユーザーと都道府県の関連テーブル CREATE TABLE `user_prefecture` ( `user_id` BIGINT PRIMARY KEY, `prefecture_id` INTEGER, CONSTRAINT `user_prefecture_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`), CONSTRAINT `user_prefecture_prefecture` FOREIGN KEY (`prefecture_id`) REFERENCES `prefecture` (`prefecture_id`) ); -- 初期データ INSERT INTO `user` (`name`) VALUES ("Ichinose"), ("Furusawa"), ("Inoriko"), ("Izu"); INSERT INTO `prefecture` (`prefecture_id`, `name`) VALUES (15, "新潟"); INSERT INTO `user_prefecture` (`user_id`, `prefecture_id`) VALUES (1, 15), (2, 15); 以下の初期データを投入してあります。

Aug 30, 2024 - 1 minute read - perl

AWS::LambdaがAWS Asia Pacific (Malaysia) Regionで利用可能になりました

AWSでアジアパシフィック(マレーシア)リージョンが利用可能になりました! Now open — AWS Asia Pacific (Malaysia) Region ついにオープン – AWS アジアパシフィック (マレーシア) リージョン それに合わせて p5-aws-lambda のビルド済みレイヤーも公開しました! Perl本体(x64): arn:aws:lambda:ap-southeast-5:445285296882:layer:perl-5-40-runtime-al2023-x86_64:1 Perl本体(arm64): arn:aws:lambda:ap-southeast-5:445285296882:layer:perl-5-40-runtime-al2023-arm64:1 Paws(x64): arn:aws:lambda:ap-southeast-5:445285296882:layer:perl-5-38-paws-al2023-x86_64:1 Paws(arm64): arn:aws:lambda:ap-southeast-5:445285296882:layer:perl-5-38-paws-al2023-arm64:1 🐰新しい地域に、喜びの声、 AWS Lambda、広がる希望。 マレーシアの空に、夢が舞う、 みんなで使おう、楽しいクラウド! うさぎも跳ねて、嬉しさ満点、 これからの未来、共に進もう! 🌟 by CodeRabbit 参考 Now open — AWS Asia Pacific (Malaysia) Region ついにオープン – AWS アジアパシフィック (マレーシア) リージョン shogo82148/p5-aws-lambda AWS::Lambda

Aug 13, 2024 - 2 minute read - go golang typescript javascript

Structured Field Values のパーサーを書いた

GoとTypeScriptで Structured Field Values のパーサーを書きました。 github.com/shogo82148/go-sfv: Go版実装 github.com/shogo82148/sfvjs: TypeScript版実装 背景 そもそも Structured Field Values (SFV) とはなにか、なぜ登場したのか、という背景はこちらの記事をどうぞ。 Structured Field Values による Header Field の構造化 HTTP APIを開発していると、アプリケーション独自のHTTPフィールドを定義することがあります。 そういうときに、標準にしたがっておいたほうが何かと楽だろう、ということでSFVを採用しました。 しかしいい感じのSFVのパーサーがなかなか見つからなかったので、自作することにした、というわけです。 Go実装 Go のモジュールとして公開されているので、いつものように go get してきましょう。 go get github.com/shogo82148/go-sfv GoでSFVをパースする DecodeItem、DecodeList、 DecodeDictionary を使います。 net/http.Header.Valuesの戻り値を直接受け取れるよう、 各関数は []string を受け取るようにしました。 package main import ( "fmt" "net/http" "github.com/shogo82148/go-sfv" ) func main() { h := make(http.Header) h.Add("Example", `2; foourl="https://foo.example.com/"`) item, err := sfv.DecodeItem(h.Values("Example")) if err != nil { panic(err) } fmt.

Aug 13, 2024 - 2 minute read - typescript javascript deno

denoland/dntがerror TS2304: Cannot find name 'ErrorOptions'で失敗する

先日npmへのパッケージ公開にチャレンジしてみました。 npmとjsrにパッケージを公開してみた (認証バッジ付) しかし2か月も経たないうちにビルドに失敗するようになってしまいました・・・。 何もしていないのに壊れた。 % deno run -A scripts/build_npm.ts [dnt] Transforming... [dnt] Running npm install... added 7 packages, and audited 8 packages in 4s found 0 vulnerabilities [dnt] Building project... [dnt] Type checking ESM... src/deps/jsr.io/@std/assert/1.0.2/assertion_error.ts:27:42 - error TS2304: Cannot find name 'ErrorOptions'. 27 constructor(message: string, options?: ErrorOptions) { ~~~~~~~~~~~~ src/deps/jsr.io/@std/assert/1.0.2/assertion_error.ts:27:42 - error TS4063: Parameter 'options' of constructor from exported class has or is using private name 'ErrorOptions'. 27 constructor(message: string, options?

Aug 12, 2024 - 3 minute read - go golang

Go言語の定数演算の精度が限界突破していた件

元ネタ: [JavaScriptの問題] var a = 0.3 - 0.2; var b = 0.2 - 0.1; var c = a==b; cの中身はどれ? — RAO(らお)@けもケP-31 (@RIORAO) 2017年10月24日 正確な実数計算をやらされるJavaScriptくん #擬竜戯画 pic.twitter.com/ipE56C2YbV — RAO(らお)@けもケP-31 (@RIORAO) 2017年10月26日 この件に関して、以下のような記事を書きました。 Go言語の浮動小数点数のお話 この記事のなかで「Goの定数は512bitの精度で計算されている」「有限精度のため、数学的な答えとは一致するとは限らない」というお話をしました。 しかし某電柱様から「記事中のコードを最新のGoで実行すると、記事の内容とは異なった結果が得られる」という情報を得ました。 問題のコード 動作が異なると報告があったのは以下のコードです。 package main import ( "fmt" ) func main() { const a = 0.3 - 0.2 const b = 0.2 - 0.1 var c = a == b fmt.Println(c) fmt.Printf("%e\n", float64(a-b)) } 数学的には 0.3 - 0.

Jul 16, 2024 - 1 minute read - firebase

Firebase Functionsがデプロイできなくなった話

新規に立ち上げたプロジェクトで firebase deploy を実行したところ、以下のエラーを吐いて失敗してしまいました。 Build failed: failed to Fetch: failed to download archive gs://gcf-sources-PROJECT_NUMBER-asia-northeast1/createUserOnUserCreate-5fd201fd-4b54-42b8-af5c-c3ca68fe3560/version-1/function-source.zip: Access to bucket gcf-sources-PROJECT_NUMBER-asia-northeast1 denied. You must grant Storage Object Viewer permission to PROJECT_NUMBER-compute@developer.gserviceaccount.com. TL;DR 以下の設定を行います。 サービスアカウント PROJECT_NUMBER-compute@developer.gserviceaccount.com に「Cloud Build サービス アカウント(roles/cloudbuild.builds.builder)」のロールを付与 サービスアカウント PROJECT_NAME@appspot.gserviceaccount.com に「Firebase 管理者(roles/firebase.admin)」「サービス アカウント ユーザー(roles/iam.serviceAccountUser)」を付与 原因 原因は「Code Buildのサービスアカウントの仕様が変更になった」ことと「デフォルトのサービスアカウントへの自動的なロール付与を無効にする設定になっていた」ことでした。 Code Buildのサービスアカウントの仕様が変更になった 今まではサービスアカウント PROJECT_NUMBER@cloudbuild.gserviceaccount.com の権限を使用してビルドしていたのが、 サービスアカウント PROJECT_NUMBER-compute@developer.gserviceaccount.com に変更になりました。 Cloud Buildサービスアカウントが仕様変更(2024年4月29日から) デフォルトのサービスアカウントへの自動的なロール付与を無効にする設定になっていた 一部のGoogle Cloudサービスでは、APIを有効化したときにデフォルトのサービスアカウントが自動的に生成されます。 このとき生成されるサービスアカウントには編集者(roles/editor)が付与されます。 しかし、今回問題になったプロジェクトでは、組織ポリシーでロール付与が無効になっていました。 デフォルトのサービス アカウントへの自動的なロール付与を無効にする この設定の影響で、サービスアカウント PROJECT_NUMBER-compute@developer.gserviceaccount.com に一切権限がない状態でした。 また、Firebase Functionsを実行するためのサービスアカウントにも一切権限がありませんでした。 対策 各サービスアカウントに適切な権限を付与します。 具体的には以下の権限を付与しました。

Jul 16, 2024 - 3 minute read - mysql

MySQL8.0で近傍検索

「Redis、PostgreSQL、MySQLで近傍検索」を公開した当時は、 MySQL 5.7 で検証を行いました。 「MySQL 8.0 ではGIS関連も強化されているぞ!」という話を聞いていたので、MySQL 8.0でも検証してみます。 (MySQL 8.0リリースから何年経ってるんだよというツッコミは置いておく) 検証環境 検証環境はDocker上で起動しました。 バージョンは2024-07-16時点で8.0系列最新の8.0.38です。 mysql> SELECT VERSION(); +-----------+ | VERSION() | +-----------+ | 8.0.38 | +-----------+ 1 row in set (0.01 sec) 最新LTSの8.4.1がリリースされていますが、Amazon RDSでは未サポートです。 マネージドサービスを利用したいので、ひとまず8.0で検証を行います。 テーブルの準備 スキーマ定義でSRIDを指定できるようになりました。 何が嬉しいかというと MySQL が「地球は丸い」ということを理解してくれます! CREATE DATABASE test; USE test; CREATE TABLE IF NOT EXISTS `geotable` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR (255) NOT NULL, `geom` POINT NOT NULL SRID 4326, PRIMARY KEY (`id`), SPATIAL KEY `geom` (`geom`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; SRIDは省略可能ですが、インデックスを利用するためには必須です。 忘れずに指定しましょう。

Jun 30, 2024 - 2 minute read - github

GitHub Artifact Attestations を試してみた

GitHub Artifact Attestations が正式リリースされました。 GitHub Artifact Attestations is generally available ベータ公開 から2カ月足らずでの正式リリースです。 早いですね。それだけ力を入れているということでしょうか。 なんか難しい単語(attestations とか provenanceとか)が並んでいて正直良くわからんのですが、とりあえず試してみましょう。 署名してみる 「S3からファイルを落とすだけのツールを作った」で作成した、 s3cli-mini で試してみます。 s3cli-miniのリリース処理は GitHub Actions 上で実行しています。 ビルドしたバイナリーは以下のリンクからダウンロード可能です。 v0.0.15 - GitHub Releases しかしこのバイナリーは本当に GitHub Actions 上でビルドしたものでしょうか? リリースバイナリーはあとから差し替えも可能です。僕が悪意のあるコードを密かに忍ばせ、再ビルドし、上書きしているかもしれません。 僕に悪意がなくとも、僕がうっかりクレデンシャルを流出させてしまい、悪意のある第三者によって上書きされるかもしれません。 そんな心配を解決するのが Artifact Attestations です。 使い方は簡単で、リリースのワークフローに actions/attest-build-provenance を呼ぶステップを追加するだけです。 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b5b65f4..31f2d6c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,7 @@ jobs: permissions: contents: write id-token: write + attestations: write runs-on: ubuntu-latest steps: @@ -35,3 +36,14 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.

Jun 25, 2024 - 1 minute read - go golang

go-retry v2 リリースのお知らせ

shogo82148/go-retry は指数的バックオフを行ってくれるライブラリです。 Goで指数的バックオフをやってくれるgo-retryを書いた v2へメジャーバージョンアップをリリースしました。 破壊的な変更が入っているのでお知らせします。 エラーのTemporaryメソッドをチェックしなくなりました DoメソッドやDoValue関数のエラーハンドリングの挙動が変更になります。 v1 までの挙動 v1のDoメソッドは戻り値のエラーが Temporary メソッドを実装している場合、 その実行結果によってリトライの挙動を変えていました。 Temporary メソッドが true を返した場合はリトライを続行します。 false を返した場合はそれ以上のリトライは無意味と判断し、リトライ処理を中断します。 この挙動は net.Error を参考に実装したものでした。 ネットワーク処理中に回復不可能なエラーが発生した場合に、リトライが自動的に中断されることを期待して実装しました。 v2 からの挙動 しかし、残念ながら Go 1.18 から Temporary メソッドは非推奨になってしまいました。 Temporaryの意味はあいまいで、利用者の意図した通りの結果を得られるとは限りません。 実際に「リトライして欲しいときにリトライしてくれない」という報告を受けました。 そういうわけで、エラーのTemporaryメソッドの戻り値は信用せず、呼ばないよう変更しました。 v1からv2への移行 多くのケースでは、インポートパスを github.com/shogo82148/go-retry から github.com/shogo82148/go-retry/v2 に変更するだけでOKなはずです。 万が一v1と同じ挙動を維持したい場合は、以下のように書き換えてください。 // v1 code policy.Do(func() error { return DoSomething() }) // v2 code policy.Do(func() error { err := DoSomething() interface temporary { Temporary() bool } var tmp temporary if errors.As(err, &tmp) && !

Jun 23, 2024 - 3 minute read - typescript

npmとjsrにパッケージを公開してみた (認証バッジ付)

先日、同時実行数を制限しながら並行実行する関数を書きました。 TypeScriptで同時実行数を制限しながら並行実行する 便利関数を作ったら他のプロジェクトから参照したいですよね。 そこでパッケージレジストリに登録してみました。 正直コピペで実装で十分なのでは?という分量ですが、パッケージ公開の練習です。 ソースコードを準備する まずは公開するソースコードを準備していきましょう。 ソースコードはGitHubで公開しました。 shogo82148/limit-concurrency - GitHub Denoの開発環境を整える TypeScriptの開発環境を整えたいのですが、Node+TypeScriptの組み合わせはプロジェクトの立ち上げは意外と面倒です。 そこで今回は Deno を使ってみることにしました。 DenoはTypeScriptの実行ランタイムとして開発されており、特別な設定なしでTypeScriptを実行できます。 Brewでインストールしました。 brew install deno 僕は最近エディターには VS Code を使っているので、Deno用の拡張機能をインストールしました。 denoland/vscode_deno インストールしただけでは有効化されません。 ワークスペースの設定ファイル .vscode/settings.json を編集して、明示的に有効化します。 { "deno.enable": true, "deno.lint": true, "editor.formatOnSave": true, "editor.defaultFormatter": "denoland.vscode-deno", "[typescript]": { "editor.defaultFormatter": "denoland.vscode-deno" }, } 開発環境が整ったらパッケージ本体のソースコードを書いていきます。 GitHub Actionsでテストを実行する パッケージとして公開するのであれば、テストを書いて、CIを回しておきたいですよね。 Deno公式がセットアップするためのアクションを公開しているので、これを利用します。 denoland/setup-deno あとは deno test コマンドを実行するだけです。 on: push: pull_request: jobs: deno: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: denoland/setup-deno@v1 with: deno-version: v1.