Skip to main content
PagerDuty 連携の詳細なガイドは、こちらをご覧ください。
1

Webhook ブリッジをデプロイする

PagerDuty の incident.resolved イベントを受信し、ポストモーテムを作成するための Devin セッションを開始する小規模なサービスを作成します。これをサーバーレス関数 (AWS Lambda、Cloudflare Worker) または軽量コンテナとしてデプロイします:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());

function verifySignature(req) {
  const secret = Buffer.from(req.headers['x-webhook-secret'] || '');
  const expected = Buffer.from(process.env.WEBHOOK_SECRET || '');
  if (!expected.length) throw new Error('WEBHOOK_SECRET environment variable is not set');
  if (secret.length !== expected.length) return false;
  return crypto.timingSafeEqual(secret, expected);
}

app.post('/pagerduty-resolved', async (req, res) => {
  if (!verifySignature(req)) return res.status(401).send('Bad signature');

  const event = req.body?.event;
  if (!event || event.event_type !== 'incident.resolved') {
    return res.sendStatus(200);
  }

  const incident = event.data;
  const title = incident.title || 'Unknown incident';
  const service = incident.service?.summary || 'unknown-service';
  const urgency = incident.urgency || 'high';
  const incidentUrl = incident.html_url || '';
  const createdAt = incident.created_at || '';
  const resolvedAt = incident.resolved_at || new Date().toISOString();

  const orgId = process.env.DEVIN_ORG_ID;
  const response = await fetch(
    `https://api.devin.ai/v3/organizations/${orgId}/sessions`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.DEVIN_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      prompt: [
        `A PagerDuty incident has been resolved. Draft a postmortem.`,
        ``,
        `Incident: "${title}"`,
        `Service: ${service}`,
        `Urgency: ${urgency}`,
        `Created: ${createdAt}`,
        `Resolved: ${resolvedAt}`,
        `Incident URL: ${incidentUrl}`,
        ``,
        `Write a structured postmortem:`,
        `1. Use the Datadog MCP to pull logs and metrics for ${service} during the incident window`,
        `2. Identify the root cause — check for deploys, config changes, or upstream failures`,
        `3. Build a detailed timeline from first alert to resolution`,
        `4. List action items to prevent recurrence`,
        `5. Post the postmortem as a PR to our docs/postmortems/ directory`,
      ].join('\n'),
      tags: ['pagerduty-postmortem', `service:${service}`],
    }),
  });

  const { session_id } = await response.json();
  console.log(`Started postmortem session ${session_id} for: ${title}`);
  res.sendStatus(200);
});

app.listen(3000);
app.devin.ai設定 > サービスユーザー で、ManageOrgSessions 権限を持つサービスユーザーを作成します。作成後に表示される API トークンをコピーし、ブリッジサービスで DEVIN_API_KEY として保存します。DEVIN_ORG_ID には組織 ID を設定します。組織 ID は、トークンを使って GET https://api.devin.ai/v3/enterprise/organizations を呼び出して取得できます。WEBHOOK_SECRET には、PagerDuty にも設定する共有シークレットを指定します。
2

PagerDuty の設定

  1. PagerDuty で Services > [your service] > Integrations に移動します
  2. Add Integration をクリックし、Generic Webhooks (v3) を選択します
  3. Webhook URL をブリッジのエンドポイントに設定します (例: https://your-bridge.example.com/pagerduty-resolved)
  4. Custom Headers で、WEBHOOK_SECRET として保存したものと同じ値の X-Webhook-Secret を追加します
  5. Event Subscription で、イベントタイプ incident.resolved で絞り込み、インシデントがクローズされた後にのみ事後検証がトリガーされるようにします
インシデントの進行中に Devin がデータの収集を開始し、解決時に事後検証を完了できるようにしたい場合は、incident.acknowledged を購読することもできます。
3

可観測性MCPを接続する(任意)

Devin は、テレメトリデータにアクセスできると、より質の高いポストモーテムを作成できます。1 つ以上の MCP を有効にして、Devin がインシデント発生期間の実データを取得できるようにします。Datadog MCPSettings > MCP Marketplace に移動し、Datadog を見つけて Enable をクリックし、API キーと Application キーを入力します。Devin はログ、メトリクス、デプロイイベント、モニター履歴を照会します。Sentry MCP — MCP Marketplace で Sentry を見つけ、Enable をクリックして OAuth フローを完了します。Devin はエラーの詳細、スタックトレース、リリースタグを取得します。接続が完了すると、Devin はテレメトリをインシデントのタイムラインに自動的に関連付け、根拠に基づくポストモーテムを作成します。詳しくは、MCP サーバーの接続をご覧ください。
4

Devinが生成するもの

PagerDuty インシデントが解決すると、Devin はインシデント発生から解決までの時間帯を分析し、構造化されたポストモーテムを作成します。Devin が生成するポストモーテムの例:
# Postmortem: Database Connection Pool Exhaustion — orders-service
**Date:** 2026-02-10 | **Duration:** 46 minutes | **Severity:** P1

## Summary
orders-service experienced connection pool exhaustion between
14:32 and 15:18 UTC, causing 502 errors for ~12% of order
placement requests.

## Timeline
- 14:15 UTC — Deploy #387 released (commit e4f29a1)
- 14:28 UTC — Connection pool usage climbed from 60% to 92%
- 14:32 UTC — Pool exhausted; PagerDuty incident triggered
- 14:38 UTC — On-call engineer acknowledged
- 14:45 UTC — Identified Deploy #387 added a new inventory
              check that opens a DB connection per line item
              without releasing it in the finally block
- 15:02 UTC — Rollback to Deploy #386 initiated
- 15:18 UTC — Connection pool recovered; incident resolved

## Root Cause
Deploy #387 introduced `checkInventoryAvailability()` in
`src/services/orders.ts:142`. The function opens a new DB
connection for each line item in an order but only releases
it on the success path. When inventory checks fail (timeout
or stock unavailable), connections leak.

Orders with 5+ line items reliably exhausted the pool within
15 minutes of the deploy.

## Action Items
- [ ] Fix connection leak: add `finally` block to release
      connection (PR #388 opened)
- [ ] Add connection pool usage monitor with alert at 80%
- [ ] Add integration test for multi-item orders with
      simulated inventory failures
- [ ] Review other DB access patterns for similar leak risks
5

ポストモーテムをカスタマイズする

チームのポストモーテムプロセスに合わせて、パイプラインを調整します。Playbook を利用すると、ポストモーテムのテンプレート (セクション、重大度の分類、必須項目、出力の保存先) を定義できます。すべてのポストモーテムを標準化するには、API リクエストで playbook_id を渡します。重大度に応じて振り分けます。 ブリッジにロジックを追加し、P1/P2 インシデントについてのみポストモーテムを生成するようにします。重大度の低いインシデントでは、完全なレポートが不要な場合があります。アーキテクチャ、サービスの担当範囲、過去のインシデントに関する Knowledge を追加します。 これにより、Devin が情報同士のつながりを把握できるようになります。たとえば、「orders-service は inventory-service に依存しており、inventory-service は高負荷時にタイムアウトが発生しやすいことで知られている」といった情報です。wiki に投稿します。 リポジトリにコミットする代わりに、セッションプロンプトを通じて Devin に Confluence、Notion、または社内 wiki へポストモーテムを投稿させます。