sixty

Node のサービス向け

どの関数、どのクエリ、どのデプロイか。

コマンド1つで入るエージェントが、エクスポートされたすべての非同期関数と、アプリが出すすべてのクエリを測ります — そして、どの関数がどのクエリを出したかを知っています。リリースは毎回1つ前と比較されるので、検出結果は時刻ではなくあなたのデプロイを名指しします。

何を測るか

エクスポートされたすべての非同期関数
どれだけ時間がかかり、そのうちどれだけが自分自身のコードで、どれだけが呼び出した先だったか。「遅くなったのは自分のコードか、呼んだ先か」が、午後ひとつではなく数値ひとつになります。
5つのクライアントにわたる全クエリ
pg、mysql2、postgres.js、MongoDB のドライバ、Prisma — 自動で見つけて計測します。Mongoose 越しでも、負荷のかかったコネクションプール越しでも。返却行数、カラム数、レスポンスサイズ、そして MongoDB については1回の読み取りが実際に何往復のネットワークを必要としたか。
どの関数がどのクエリを出したか
残りを読む価値のあるものにしている部分です。クエリはその上にある関数に帰属するので、N+1 はループを持っている関数の上に出ます。いつも問題なく見えていたクエリの側に散らばりません。
データベースが答えるために何をしたか
Postgres には各文のプランを尋ねます — パラメータを一度も束縛せずに、なので、あなたの値は一切関わりません。MySQL は代わりに performance_schema から読みます。返却行あたりの走査行数と、そもそもインデックスが使われたかどうか。どちらも同じ検出として届きます。「これはそのテーブルをインデックスなしで読んでいる」と。
あなたの HTTP ルート、受けと出し
処理したリクエストと、他人の API を待っていた時間 — 遅いサードパーティが「あなたのコードが遅い」として報告されなくなります。

何を見つけるか

どれも1つ前のリリースと比較されます。だから検出結果は、日付ではなく変更を名指しします。

前のリリースにはなかった N+1

1リクエストにつき1回だったデータベース呼び出しが、いまは14回。デプロイに紐づいているので、それを持ち込んだリリースを名指しします。

テーブル全体を読み始めたクエリ

1回あたりの行数が30から30,000へ。ステージング規模のデータと温まったデータベースが相手ならほとんど時計は動きません — そして1週間後に本番を落とします。

インデックスを使わなくなったクエリ

ここで唯一、症状ではなく原因を名指しする検出です。まだ何も遅くないうちに届くことがよくあります。テーブルがまだ小さくてスキャンでも問題ない段階で、そして数週間後、小さくなくなったときに障害になります。

自分のコードが遅くなっている

呼び出した先ではなく関数自身の中で使われた時間 — 分けてあるので、1回目で正しいファイルを開けます。

数百回のネットワーク待ちに化けた読み取り

MongoDB はカーソルをバッチで返します。結果が1バッチを超えると、1回の読み取りが数十回〜数百回の連続した往復になります — ドキュメントは同じなので、システムの中で動くのは時計だけです。

いまはループの中で呼ばれているもの

1回あたりは変わらず — 同じ速さ、同じデータ — それでも、以前は1回だった呼び出しが数百回になっています。

静かに何も返さなくなったクエリ

成功し、エラーもなく、遅くもなく、以前は行が返っていたのに空で返ってきた。この種のサービスが壊れる最も一般的な形は、数字を大きくではなく小さくします。

フィードに何が届くか

読むためのダッシュボードではありません。検出1件につきカード1枚。数値と、それを変えたリリースと、コーディングエージェントが修正を書くのに必要な証拠が付いています。

これは `pnpm e2e` が出力する数値で、誰がこのリポジトリをクローンしても同じです。サービスを用意し、本物の回帰を2つ含んだリリースを出し、それを検出します — つまりここに私たちが選んだ数字は1つもありません。

行数orders.getUserOrders
30行30,000行1000×

リファクタリングの途中で WHERE 句が消え、関数はテーブル全体を取ってきて JavaScript で絞り込んでいます。温まったデータベースでは、時計はほとんど動きませんでした。

リリース v2 以降、v1 との比較

N+1orders.enrichOrders
1本14本14×

クエリがループの中に移りました。どれも速いので、1つのリクエストとして見ればおかしなところはありません — 変わったのは回数だけです。

リリース v2 以降、v1 との比較

導入方法

すでに開いているコーディングエージェントに渡してください。リポジトリを読み、それが Next の設定なのか、Vite プラグインなのか、起動コマンドなのかを判断して組み込みます — そして同じ会話の中で、見つかったものを直します。

claude mcp add sixty \
  -e SIXTY_API_KEY=sixty_sk_… \
  -e SIXTY_ENDPOINT=https://ingest.sixty.sh \
  -- npx -y @sixty-sh/mcp

# or by hand, in your server entry:
import { init } from '@sixty-sh/node'
init()

リリース識別子は Vercel、Render、Railway、Fly、Heroku、GitHub Actions から自動で拾われます。最初の比較は次のデプロイのあとに届きます。1つのリリースには比べる相手がないからです。

できないこと

  • MySQL と MongoDB はプランのツリーを返しません。MySQL の EXPLAIN には実際のパラメータ値が、MongoDB の explain には実際のフィルタが必要で、このエージェントは値を見た瞬間に捨てます — なので MySQL では代わりに performance_schema から結論を読み、MongoDB についてはまだ何もありません。
  • 非同期ジェネレータはビルド時の変換が飛ばします。包んでしまうと「呼び出し側がイテレータを受け取るまでの時間」を測ることになり、それは誰も欲しくない数値だからです。
  • エージェントが測るのは JavaScript から届く範囲です。ネイティブモジュールの中や別プロセスで使われた時間は、待ち時間としてしか見えません。

これが理由でここに来たのなら

最後の変更が何をしたのか、確かめてください。

試してみる

別のものを作っていますか? Python のサービス、Lovable のアプリ、React Native のアプリ のページもあります — 見えるものが違うので、内容も違います。

Node・Postgres・MySQL・MongoDB 向けパフォーマンス監視 — Sixty