Convex 運用監視ダッシュボード構築:Datadog/Grafana 連携と SLO 設計
Convex はリアルタイムデータベースと API を提供する BaaS(Backend as a Service)として注目を集めています。しかし、本番環境で安定運用するには、適切な監視体制の構築が欠かせません。本記事では、Convex の運用監視ダッシュボードを Datadog や Grafana と連携させ、SLO(Service Level Objective)を設計する方法を詳しく解説していきます。
実際の運用現場で使える具体的な設定方法と、信頼性の高いサービスを維持するためのベストプラクティスをお伝えしますので、ぜひ最後までご覧ください。
背景
Convex の運用監視が重要な理由
Convex は WebSocket を使ったリアルタイム通信を基盤としており、従来の REST API とは異なる監視アプローチが必要です。リアルタイム性を活かしたアプリケーションでは、わずかな遅延やエラーがユーザー体験に直結するため、継続的な監視が不可欠になります。
また、Convex は BaaS として様々な処理を担当するため、データベースクエリ、関数実行、認証処理など、複数のレイヤーでの監視が求められます。これらの処理をまとめて可視化し、問題を早期発見できる体制を整えることが、サービスの信頼性向上につながるのです。
以下の図は、Convex アプリケーションにおける監視対象の全体像を示しています。
mermaidflowchart TB
client["クライアント<br/>アプリケーション"]
convex["Convex<br/>Backend"]
monitoring["監視システム<br/>(Datadog/Grafana)"]
subgraph "監視対象"
queries["クエリ実行時間"]
mutations["ミューテーション<br/>成功率"]
connections["WebSocket<br/>接続数"]
errors["エラー発生率"]
end
client -->|WebSocket| convex
convex -->|メトリクス| queries
convex -->|メトリクス| mutations
convex -->|メトリクス| connections
convex -->|メトリクス| errors
queries --> monitoring
mutations --> monitoring
connections --> monitoring
errors --> monitoring
この図からわかるように、クライアントからの WebSocket 接続を起点に、複数の監視ポイントが存在します。これらのメトリクスを適切に収集し、分析することで、サービスの健全性を保つことができます。
監視ツールの選択肢
運用監視ツールとして、Datadog と Grafana は異なる特徴を持っています。
| # | ツール | 特徴 | 適したケース |
|---|---|---|---|
| 1 | Datadog | フルマネージドで統合監視に強い | SaaS 全体の監視、アラート自動化 |
| 2 | Grafana | オープンソースでカスタマイズ性が高い | コスト重視、柔軟なダッシュボード |
| 3 | 両方併用 | 異なる強みを活かせる | 大規模運用、複数チーム体制 |
Datadog は APM(Application Performance Monitoring)機能が充実しており、ログ、メトリクス、トレースを一元管理できます。一方、Grafana は Prometheus などのデータソースと組み合わせることで、コストを抑えながら柔軟な可視化が可能です。
課題
Convex 固有の監視課題
Convex を運用する際、いくつかの特有の課題に直面します。
まず、リアルタイム性の担保が最大の課題です。WebSocket 接続が切断されると、リアルタイム更新が停止し、ユーザー体験が大きく損なわれます。接続状態を常時監視し、異常を即座に検知する必要があります。
次に、関数実行のパフォーマンス監視が重要です。Convex の関数は TypeScript で記述されますが、実行時間が長くなると、アプリケーション全体のレスポンスに影響します。どの関数がボトルネックになっているかを特定できる仕組みが必要でしょう。
さらに、エラー率の可視化も課題となります。Convex では、クエリエラー、ミューテーションエラー、認証エラーなど、様々なエラーが発生する可能性があります。これらを分類し、優先度をつけて対応する体制が求められます。
以下の図は、これらの課題がどのように関連しているかを示しています。
mermaidflowchart LR
realtime["リアルタイム性の低下"]
performance["関数実行の遅延"]
errors["エラー発生"]
user["ユーザー体験の悪化"]
realtime -->|接続断| user
performance -->|レスポンス遅延| user
errors -->|機能停止| user
realtime -.->|連鎖的影響| performance
performance -.->|タイムアウト| errors
このように、各課題は独立しているように見えて、実は連鎖的に影響し合います。そのため、包括的な監視アプローチが不可欠なのです。
既存の監視ツールとの連携の難しさ
Convex は比較的新しいプラットフォームであり、既存の監視ツールとのネイティブ連携が限られています。Datadog や Grafana に直接メトリクスを送信する標準機能がないため、独自の連携方法を構築する必要があります。
また、Convex のログフォーマットが独自であるため、ログ解析にもひと工夫が必要です。標準的なログパーサーでは解釈できない情報が含まれており、カスタムパーサーの実装が求められるケースもあるでしょう。
解決策
監視アーキテクチャの設計
Convex の監視を効果的に行うには、以下のアーキテクチャを採用することをお勧めします。
まず、Convex の内部メトリクスを取得する仕組みを構築します。Convex Dashboard から提供される情報を API 経由で取得し、外部監視ツールに転送する橋渡し役を作ります。
次に、カスタムメトリクスの収集を行います。アプリケーション側から独自のメトリクスを Convex の関数経由で記録し、それを監視ツールに送信します。
最後に、ダッシュボードの統合を実現します。Datadog や Grafana で Convex 専用のダッシュボードを作成し、重要な指標を一目で把握できるようにします。
以下の図は、推奨する監視アーキテクチャの全体像です。
mermaidflowchart TB
convex_app["Convex アプリケーション"]
convex_api["Convex API"]
collector["メトリクス収集<br/>サービス"]
subgraph "監視基盤"
datadog["Datadog"]
prometheus["Prometheus"]
grafana["Grafana"]
end
subgraph "アラート"
slack["Slack 通知"]
pagerduty["PagerDuty"]
end
convex_app -->|カスタムメトリクス| collector
convex_api -->|システムメトリクス| collector
collector -->|転送| datadog
collector -->|転送| prometheus
prometheus --> grafana
datadog --> slack
datadog --> pagerduty
grafana --> slack
この構成により、Convex から得られる様々なメトリクスを一元的に収集し、適切な監視ツールに振り分けることができます。
Datadog 連携の実装
Datadog と Convex を連携させるには、メトリクス収集サービスを経由する方法が最も実用的です。
メトリクス収集サービスの構築
まず、Convex のメトリクスを収集する専用サービスを Node.js で実装します。
typescript// types/metrics.ts
export interface ConvexMetrics {
functionName: string;
executionTime: number;
status: 'success' | 'error';
timestamp: number;
errorType?: string;
}
export interface DatadogConfig {
apiKey: string;
appKey: string;
site: string;
}
メトリクスの型定義を行い、Convex 関数の実行情報と Datadog の設定情報を明確にします。
次に、Datadog にメトリクスを送信するクライアントを実装します。
typescript// lib/datadog-client.ts
import { v2 } from '@datadog/datadog-api-client';
import type {
ConvexMetrics,
DatadogConfig,
} from '../types/metrics';
export class DatadogClient {
private metricsApi: v2.MetricsApi;
constructor(config: DatadogConfig) {
const configuration = v2.createConfiguration({
authMethods: {
apiKeyAuth: config.apiKey,
appKeyAuth: config.appKey,
},
});
// Datadog のサイト設定(例: datadoghq.com)
configuration.setServerVariables({
site: config.site,
});
this.metricsApi = new v2.MetricsApi(configuration);
}
// メトリクスを送信するメソッド
async sendMetrics(
metrics: ConvexMetrics[]
): Promise<void> {
// 次のコードブロックで実装
}
}
Datadog の公式クライアントライブラリを使用し、認証情報を設定します。この構成により、安全にメトリクスを送信できます。
メトリクス送信の実装
実際にメトリクスを Datadog に送信する処理を実装します。
typescript// lib/datadog-client.ts(続き)
async sendMetrics(metrics: ConvexMetrics[]): Promise<void> {
try {
const series = metrics.map((metric) => ({
metric: `convex.function.${metric.functionName}`,
type: 1, // gauge type
points: [
{
timestamp: Math.floor(metric.timestamp / 1000),
value: metric.executionTime,
},
],
tags: [
`status:${metric.status}`,
metric.errorType ? `error_type:${metric.errorType}` : '',
].filter(Boolean),
}));
const params: v2.MetricsApiSubmitMetricsRequest = {
body: { series },
};
await this.metricsApi.submitMetrics(params);
console.log(`Successfully sent ${metrics.length} metrics to Datadog`);
} catch (error) {
console.error('Failed to send metrics to Datadog:', error);
throw error;
}
}
メトリクスを Datadog のフォーマットに変換し、バッチで送信します。エラーハンドリングも適切に行い、送信失敗時にログを出力します。
Convex 関数からのメトリクス記録
Convex の関数内でメトリクスを記録する仕組みを実装します。
typescript// convex/lib/metrics.ts
import { v } from 'convex/values';
import { mutation } from '../_generated/server';
export const recordMetric = mutation({
args: {
functionName: v.string(),
executionTime: v.number(),
status: v.union(
v.literal('success'),
v.literal('error')
),
errorType: v.optional(v.string()),
},
handler: async (ctx, args) => {
// メトリクスをデータベースに保存
await ctx.db.insert('metrics', {
functionName: args.functionName,
executionTime: args.executionTime,
status: args.status,
errorType: args.errorType,
timestamp: Date.now(),
});
},
});
この mutation を使用することで、任意の Convex 関数からメトリクスを記録できます。
メトリクス収集ワーカーの実装
定期的にメトリクスを収集し、Datadog に送信するワーカーを実装します。
typescript// workers/metrics-collector.ts
import { ConvexHttpClient } from 'convex/browser';
import { DatadogClient } from '../lib/datadog-client';
import { api } from '../convex/_generated/api';
const convexClient = new ConvexHttpClient(
process.env.CONVEX_URL!
);
const datadogClient = new DatadogClient({
apiKey: process.env.DATADOG_API_KEY!,
appKey: process.env.DATADOG_APP_KEY!,
site: process.env.DATADOG_SITE || 'datadoghq.com',
});
async function collectAndSendMetrics() {
try {
// Convex から最新のメトリクスを取得
const metrics = await convexClient.query(
api.metrics.getRecent,
{
limit: 100,
}
);
if (metrics.length > 0) {
await datadogClient.sendMetrics(metrics);
console.log(
`Collected and sent ${metrics.length} metrics`
);
}
} catch (error) {
console.error('Error in metrics collection:', error);
}
}
// 1分ごとに実行
setInterval(collectAndSendMetrics, 60000);
この処理により、Convex に蓄積されたメトリクスを定期的に Datadog に転送できます。
Grafana 連携の実装
Grafana との連携では、Prometheus をデータソースとして使用する方法が一般的です。
Prometheus Exporter の実装
Convex のメトリクスを Prometheus 形式で公開する Exporter を作成します。
typescript// exporters/prometheus-exporter.ts
import express from 'express';
import { register, Counter, Histogram } from 'prom-client';
import { ConvexHttpClient } from 'convex/browser';
import { api } from '../convex/_generated/api';
const app = express();
const convexClient = new ConvexHttpClient(
process.env.CONVEX_URL!
);
// メトリクスの定義
const functionExecutionTime = new Histogram({
name: 'convex_function_execution_seconds',
help: 'Execution time of Convex functions in seconds',
labelNames: ['function_name', 'status'],
buckets: [0.1, 0.5, 1, 2, 5],
});
const functionExecutionCount = new Counter({
name: 'convex_function_execution_total',
help: 'Total number of Convex function executions',
labelNames: ['function_name', 'status'],
});
Prometheus のクライアントライブラリを使用し、Convex 関数の実行時間と実行回数を測定するメトリクスを定義します。
メトリクス更新処理
定期的に Convex からメトリクスを取得し、Prometheus のメトリクスを更新します。
typescript// exporters/prometheus-exporter.ts(続き)
async function updateMetrics() {
try {
const metrics = await convexClient.query(
api.metrics.getRecent,
{
limit: 1000,
}
);
metrics.forEach((metric) => {
// 実行時間をヒストグラムに記録
functionExecutionTime
.labels(metric.functionName, metric.status)
.observe(metric.executionTime / 1000); // ミリ秒から秒に変換
// 実行回数をカウンター に記録
functionExecutionCount
.labels(metric.functionName, metric.status)
.inc();
});
console.log(
`Updated metrics for ${metrics.length} executions`
);
} catch (error) {
console.error('Failed to update metrics:', error);
}
}
// 30秒ごとにメトリクスを更新
setInterval(updateMetrics, 30000);
この処理により、Prometheus が Exporter からメトリクスをスクレイプする際に、最新の情報を提供できます。
Exporter エンドポイントの公開
Prometheus がスクレイプするエンドポイントを公開します。
typescript// exporters/prometheus-exporter.ts(続き)
app.get('/metrics', async (req, res) => {
try {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
} catch (error) {
res.status(500).end(error);
}
});
const PORT = process.env.EXPORTER_PORT || 9090;
app.listen(PORT, () => {
console.log(
`Prometheus exporter listening on port ${PORT}`
);
});
このエンドポイントを通じて、Prometheus は定期的にメトリクスを収集できます。
Prometheus 設定
Prometheus の設定ファイルに、Convex Exporter をスクレイプ対象として追加します。
yaml# prometheus.yml
global:
scrape_interval: 30s
evaluation_interval: 30s
scrape_configs:
- job_name: 'convex-metrics'
static_configs:
- targets: ['localhost:9090']
metric_relabel_configs:
- source_labels: [__name__]
regex: 'convex_.*'
action: keep
この設定により、Prometheus は 30 秒ごとに Convex のメトリクスを収集します。
Grafana ダッシュボードの作成
Grafana でダッシュボードを作成するための JSON 定義を用意します。
json{
"dashboard": {
"title": "Convex Monitoring Dashboard",
"panels": [
{
"id": 1,
"title": "Function Execution Time (p95)",
"type": "graph",
"targets": [
{
"expr": "histogram_quantile(0.95, rate(convex_function_execution_seconds_bucket[5m]))",
"legendFormat": "{{function_name}}"
}
]
},
{
"id": 2,
"title": "Function Execution Rate",
"type": "graph",
"targets": [
{
"expr": "rate(convex_function_execution_total[5m])",
"legendFormat": "{{function_name}} - {{status}}"
}
]
}
]
}
}
このダッシュボード定義を Grafana にインポートすることで、すぐに使える監視画面が構築できます。
SLO 設計の実装
SLO(Service Level Objective)を設計し、サービスの信頼性目標を明確にします。
SLO の定義
Convex アプリケーションにおける重要な SLO を定義します。
| # | SLO 項目 | 目標値 | 測定方法 |
|---|---|---|---|
| 1 | 可用性 | 99.9% | 成功したリクエスト数 / 全リクエスト数 |
| 2 | レイテンシ(p95) | 500ms 以下 | 関数実行時間の 95 パーセンタイル |
| 3 | エラー率 | 0.1% 以下 | エラー数 / 全リクエスト数 |
| 4 | WebSocket 接続安定性 | 99.5% | 接続維持時間 / 総接続時間 |
これらの SLO を基準に、サービスの健全性を評価します。
SLO 計算処理の実装
SLO を自動計算する処理を実装します。
typescript// lib/slo-calculator.ts
interface SLOMetrics {
availability: number;
latencyP95: number;
errorRate: number;
connectionStability: number;
}
export class SLOCalculator {
// 可用性を計算
calculateAvailability(
successfulRequests: number,
totalRequests: number
): number {
if (totalRequests === 0) return 100;
return (successfulRequests / totalRequests) * 100;
}
// p95レイテンシを計算
calculateP95Latency(executionTimes: number[]): number {
if (executionTimes.length === 0) return 0;
const sorted = [...executionTimes].sort(
(a, b) => a - b
);
const index = Math.floor(sorted.length * 0.95);
return sorted[index];
}
// エラー率を計算
calculateErrorRate(
errors: number,
totalRequests: number
): number {
if (totalRequests === 0) return 0;
return (errors / totalRequests) * 100;
}
}
各 SLO 指標を計算するメソッドを実装し、数値として評価できるようにします。
SLO 監視の自動化
SLO の達成状況を定期的に確認し、違反時にアラートを発生させます。
typescript// workers/slo-monitor.ts
import { SLOCalculator } from '../lib/slo-calculator';
import { ConvexHttpClient } from 'convex/browser';
import { api } from '../convex/_generated/api';
const convexClient = new ConvexHttpClient(
process.env.CONVEX_URL!
);
const sloCalculator = new SLOCalculator();
// SLOのしきい値
const SLO_THRESHOLDS = {
availability: 99.9,
latencyP95: 500,
errorRate: 0.1,
connectionStability: 99.5,
};
async function checkSLOs() {
try {
// 過去1時間のメトリクスを取得
const metrics = await convexClient.query(
api.metrics.getLastHour
);
const successfulRequests = metrics.filter(
(m) => m.status === 'success'
).length;
const totalRequests = metrics.length;
const errors = metrics.filter(
(m) => m.status === 'error'
).length;
const executionTimes = metrics.map(
(m) => m.executionTime
);
// SLOを計算
const availability =
sloCalculator.calculateAvailability(
successfulRequests,
totalRequests
);
const latencyP95 =
sloCalculator.calculateP95Latency(executionTimes);
const errorRate = sloCalculator.calculateErrorRate(
errors,
totalRequests
);
// しきい値チェック
if (availability < SLO_THRESHOLDS.availability) {
await sendAlert(
'Availability SLO violation',
availability
);
}
if (latencyP95 > SLO_THRESHOLDS.latencyP95) {
await sendAlert('Latency SLO violation', latencyP95);
}
if (errorRate > SLO_THRESHOLDS.errorRate) {
await sendAlert(
'Error rate SLO violation',
errorRate
);
}
console.log('SLO check completed:', {
availability,
latencyP95,
errorRate,
});
} catch (error) {
console.error('Failed to check SLOs:', error);
}
}
// アラート送信処理
async function sendAlert(
message: string,
value: number
): Promise<void> {
// Slack や PagerDuty にアラートを送信
console.error(
`ALERT: ${message} - Current value: ${value}`
);
}
// 5分ごとにSLOをチェック
setInterval(checkSLOs, 300000);
この自動監視により、SLO 違反を即座に検知し、迅速な対応が可能になります。
具体例
実際のダッシュボード構築例
ここでは、実際に Datadog でダッシュボードを構築する手順を示します。
ダッシュボード定義の作成
Datadog のダッシュボード定義を Terraform で管理する例です。
hcl# terraform/datadog-dashboard.tf
resource "datadog_dashboard" "convex_monitoring" {
title = "Convex Monitoring Dashboard"
description = "Convex アプリケーションの総合監視ダッシュボード"
layout_type = "ordered"
widget {
timeseries_definition {
title = "関数実行時間(p95)"
request {
q = "p95:convex.function.execution_time{*}"
display_type = "line"
}
yaxis {
label = "実行時間 (ms)"
scale = "linear"
}
}
}
widget {
query_value_definition {
title = "現在のエラー率"
request {
q = "sum:convex.function.errors{*}.as_rate()"
aggregator = "avg"
}
precision = 2
}
}
}
Infrastructure as Code により、ダッシュボードをバージョン管理し、再現可能な形で管理できます。
アラートルールの設定
SLO 違反時のアラートルールを定義します。
hcl# terraform/datadog-monitors.tf
resource "datadog_monitor" "high_error_rate" {
name = "Convex - High Error Rate"
type = "metric alert"
message = <<-EOF
Convex のエラー率がしきい値を超えています。
現在のエラー率: {{value}}%
しきい値: 0.1%
@slack-convex-alerts
EOF
query = "avg(last_5m):( sum:convex.function.errors{*}.as_count() / sum:convex.function.total{*}.as_count() ) * 100 > 0.1"
monitor_thresholds {
critical = 0.1
warning = 0.05
}
notify_no_data = false
renotify_interval = 60
tags = ["service:convex", "environment:production"]
}
このアラート設定により、エラー率が 0.1% を超えた場合に Slack へ通知が送信されます。
レイテンシ監視アラート
レイテンシが目標値を超えた場合のアラートも設定します。
hcl# terraform/datadog-monitors.tf(続き)
resource "datadog_monitor" "high_latency" {
name = "Convex - High Latency (p95)"
type = "metric alert"
message = <<-EOF
Convex の関数実行時間(p95)がしきい値を超えています。
現在の実行時間: {{value}}ms
しきい値: 500ms
@slack-convex-alerts @pagerduty
EOF
query = "avg(last_10m):p95:convex.function.execution_time{*} > 500"
monitor_thresholds {
critical = 500
warning = 400
}
notify_no_data = false
renotify_interval = 30
require_full_window = false
tags = ["service:convex", "environment:production", "slo:latency"]
}
レイテンシの悪化は即座に対応が必要なため、PagerDuty にも通知を送信します。
Grafana ダッシュボードの具体例
Grafana で作成するダッシュボードの詳細な設定例を示します。
ダッシュボード全体の構成
Grafana ダッシュボードを JSON で定義します。
json{
"dashboard": {
"title": "Convex 運用監視ダッシュボード",
"tags": ["convex", "monitoring"],
"timezone": "Asia/Tokyo",
"panels": [
{
"id": 1,
"title": "可用性(直近24時間)",
"type": "stat",
"gridPos": { "h": 8, "w": 6, "x": 0, "y": 0 },
"targets": [
{
"expr": "(sum(rate(convex_function_execution_total{status=\"success\"}[24h])) / sum(rate(convex_function_execution_total[24h]))) * 100",
"legendFormat": "可用性"
}
],
"fieldConfig": {
"defaults": {
"unit": "percent",
"thresholds": {
"mode": "absolute",
"steps": [
{ "value": 0, "color": "red" },
{ "value": 99, "color": "yellow" },
{ "value": 99.9, "color": "green" }
]
}
}
}
}
]
}
}
この設定により、可用性を色分けして直感的に把握できるダッシュボードが作成されます。
関数別パフォーマンス監視パネル
各関数のパフォーマンスを個別に監視するパネルを追加します。
json{
"id": 2,
"title": "関数別実行時間(p95)",
"type": "graph",
"gridPos": { "h": 8, "w": 12, "x": 6, "y": 0 },
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(convex_function_execution_seconds_bucket[5m])) by (function_name, le))",
"legendFormat": "{{function_name}}"
}
],
"fieldConfig": {
"defaults": {
"unit": "ms",
"custom": {
"drawStyle": "line",
"lineInterpolation": "smooth",
"fillOpacity": 10
}
}
},
"options": {
"legend": {
"displayMode": "table",
"placement": "right",
"calcs": ["lastNotNull", "max", "mean"]
}
}
}
このパネルでは、各関数の p95 レイテンシを時系列グラフで表示し、ボトルネックを特定しやすくします。
エラー率トレンドパネル
エラー率の推移を監視するパネルも重要です。
json{
"id": 3,
"title": "エラー率トレンド",
"type": "graph",
"gridPos": { "h": 8, "w": 6, "x": 18, "y": 0 },
"targets": [
{
"expr": "(sum(rate(convex_function_execution_total{status=\"error\"}[5m])) / sum(rate(convex_function_execution_total[5m]))) * 100",
"legendFormat": "エラー率"
}
],
"fieldConfig": {
"defaults": {
"unit": "percent",
"custom": {
"drawStyle": "line",
"lineInterpolation": "smooth"
}
}
},
"alert": {
"conditions": [
{
"evaluator": {
"type": "gt",
"params": [0.1]
},
"operator": {
"type": "and"
},
"query": {
"params": ["A", "5m", "now"]
},
"type": "query"
}
],
"executionErrorState": "alerting",
"frequency": "1m",
"handler": 1,
"name": "エラー率アラート",
"noDataState": "no_data",
"notifications": []
}
}
このパネルでは、エラー率が 0.1% を超えた場合にアラートが発生するよう設定されています。
トラブルシューティング事例
実際の運用で発生しやすい問題とその対処法を紹介します。
問題 1: メトリクス送信の遅延
エラーコード: Error 429: Too Many Requests
エラーメッセージ:
vbnetError: Failed to send metrics to Datadog
Status: 429
Message: API rate limit exceeded. Current rate: 150 req/s, Limit: 100 req/s
発生条件: メトリクス送信の頻度が高すぎる場合や、バッチサイズが小さすぎて API リクエスト数が増加した場合に発生します。
解決方法:
- バッチサイズを増やす
- 送信頻度を調整する
- バックオフ戦略を実装する
typescript// lib/datadog-client.ts(改善版)
export class DatadogClient {
private queue: ConvexMetrics[] = [];
private readonly BATCH_SIZE = 100;
private readonly RETRY_DELAY = 5000;
async sendMetrics(
metrics: ConvexMetrics[]
): Promise<void> {
this.queue.push(...metrics);
// バッチサイズに達したら送信
if (this.queue.length >= this.BATCH_SIZE) {
await this.flush();
}
}
private async flush(): Promise<void> {
if (this.queue.length === 0) return;
const batch = this.queue.splice(0, this.BATCH_SIZE);
try {
await this.sendBatch(batch);
} catch (error: any) {
if (error.statusCode === 429) {
// レート制限エラーの場合、キューに戻して遅延
this.queue.unshift(...batch);
await new Promise((resolve) =>
setTimeout(resolve, this.RETRY_DELAY)
);
await this.flush();
} else {
throw error;
}
}
}
}
このバッチ処理とリトライ戦略により、API レート制限エラーを回避できます。
問題 2: Prometheus Exporter の停止
エラーコード: ECONNREFUSED
エラーメッセージ:
javascriptError: connect ECONNREFUSED 127.0.0.1:9090
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1148:16)
発生条件: Exporter プロセスがクラッシュした場合や、ネットワーク問題で接続できない場合に発生します。
解決方法:
- ヘルスチェックエンドポイントを追加
- プロセス監視を導入
- 自動再起動を設定
typescript// exporters/prometheus-exporter.ts(改善版)
import express from 'express';
const app = express();
// ヘルスチェックエンドポイント
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
uptime: process.uptime(),
timestamp: Date.now(),
});
});
// グレースフルシャットダウン
process.on('SIGTERM', () => {
console.log(
'SIGTERM received, closing server gracefully'
);
server.close(() => {
console.log('Server closed');
process.exit(0);
});
});
const server = app.listen(PORT, () => {
console.log(`Exporter running on port ${PORT}`);
});
プロセス管理ツール(PM2 や systemd)と組み合わせることで、安定した運用が可能になります。
問題 3: SLO 計算の不正確さ
エラーコード: なし(論理エラー)
発生条件: データの欠損やタイムスタンプのずれにより、SLO 計算が不正確になる場合があります。
解決方法:
- データ検証を追加
- 集計期間を明確にする
- 異常値を除外する
typescript// lib/slo-calculator.ts(改善版)
export class SLOCalculator {
calculateP95Latency(executionTimes: number[]): number {
// データ検証
const validTimes = executionTimes.filter(
(time) => time > 0 && time < 60000 // 60秒以上は異常値として除外
);
if (validTimes.length === 0) {
console.warn(
'No valid execution times for p95 calculation'
);
return 0;
}
// 最低10サンプル必要
if (validTimes.length < 10) {
console.warn(
`Insufficient samples for accurate p95: ${validTimes.length}`
);
}
const sorted = [...validTimes].sort((a, b) => a - b);
const index = Math.floor(sorted.length * 0.95);
return sorted[index];
}
}
データ品質を向上させることで、より正確な SLO 評価が可能になります。
まとめ
本記事では、Convex の運用監視ダッシュボードを構築する方法について、Datadog と Grafana の連携、そして SLO 設計の観点から詳しく解説してきました。
Convex はリアルタイム性の高い BaaS であるため、従来の REST API とは異なる監視アプローチが必要です。メトリクス収集サービスを経由して Datadog や Prometheus にデータを送信し、Grafana で可視化する構成を採用することで、効果的な監視体制を構築できます。
SLO の設計では、可用性、レイテンシ、エラー率、接続安定性という 4 つの重要な指標を定義し、自動監視する仕組みを実装しました。これにより、サービスの信頼性を定量的に評価し、改善につなげることができるでしょう。
実際の運用では、API レート制限やプロセスの停止など、様々な問題が発生する可能性があります。本記事で紹介したトラブルシューティング事例を参考に、堅牢な監視システムを構築していただければと思います。
監視体制の整備は、サービスの成長とともに継続的に改善していくべき領域です。まずは基本的なメトリクスの収集から始め、運用の中で得られた知見をもとに、より高度な監視へと進化させていくことをお勧めします。
関連リンク
articleConvex 運用監視ダッシュボード構築:Datadog/Grafana 連携と SLO 設計
articleConvex で「Permission denied」多発時の原因特定:認可/コンテキスト/引数を総点検
articleConvex でリアルタイムダッシュボード:KPI/閾値アラート/役割別ビューの実装例
articleConvex で Presence(在席)機能を実装:ユーザーステータスのリアルタイム同期
articleConvex で実践する CQRS/イベントソーシング:履歴・再生・集約の設計ガイド
articleConvex クエリ/ミューテーション/アクション チートシート【保存版シンタックス】
articleGitHub Copilot Enterprise 初期構築:SSO/SCIM・ポリシー・配布ロールアウト設計
articleDevin が強い開発フェーズはどこ?要件定義~運用までの適合マップ
articleConvex 運用監視ダッシュボード構築:Datadog/Grafana 連携と SLO 設計
articleGitHub Actions で PostgreSQL/Redis を services で立ち上げるテスト基盤レシピ
articleGit の依存取り込み比較:subtree vs submodule — 運用コストと安全性の実態
articleComfyUI チートシート:よく使うノード 50 個の役割と接続例早見表
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来