Advanced (अपडेट: 2/6/2026)

Claude Code के साथ Event-Driven Architecture: व्यावहारिक गाइड

Claude Code से event-driven design की समीक्षा: contract, idempotency, retry, DLQ, observability और pitfalls.

Claude Code के साथ Event-Driven Architecture: व्यावहारिक गाइड

Event-driven architecture सुनने में साफ और scalable लगती है, लेकिन बिना अनुशासन के यह production incident को और मुश्किल बना सकती है। अगर Claude Code से केवल यह कहा जाए कि “system को loosely coupled बना दो”, और event name, payload contract, idempotency, retry, dead-letter queue, replay और logging की सीमा तय न हो, तो demo चल सकता है पर failure debug करना कठिन होगा।

इस लेख में Claude Code को reviewer और implementation assistant की तरह इस्तेमाल किया गया है, unquestioned architect की तरह नहीं। Architecture boundary इंसान तय करता है; Claude Code event naming, schema compatibility, duplicate delivery, ordering assumption, retry, DLQ, replay और observability की कमियां खोजता है। उदाहरणों में SaaS signup, payment Webhook से fulfillment, audit log stream और notification pipeline शामिल हैं।

Event-driven architecture का आधार

Event-driven architecture में एक service कोई fact publish करती है जो पहले ही हो चुका है, और दूसरी services उस fact पर react करती हैं। Event command नहीं है। com.claudecodelab.user.created.v1 का मतलब है “user बन चुका है”, यह नहीं कि “user बनाओ”। यही फर्क producer को consumer की internal logic से अलग रखता है।

शुरुआत के लिए चार शब्द काफी हैं। Producer event publish करता है। Consumer event receive और process करता है। Event bus या queue delivery path है। Schema payload का contract है, जैसे userId string होगी और email email format में होगा। Payload event का data है; schema उस data की boundary है।

Common event envelope के लिए CloudEvents और CloudEvents spec देखें। AWS में event routing समझने के लिए Amazon EventBridge उपयोगी है। Observability के लिए OpenTelemetry docs traces, metrics और logs को व्यवस्थित करने का अच्छा आधार देते हैं।

Claude Code को शुरुआत में “पूरी architecture design करो” न कहें। उसे existing API, database tables, Webhook entry point और incident recovery rules दें। फिर उससे पूछें: क्या event name साफ है, क्या payload backward compatible है, duplicate delivery safe है, replay संभव है, और क्या event producer से consumer तक trace हो सकता है?

पहले event contract लिखें

Handler code से पहले contract चाहिए। Contract नहीं होगा तो हर consumer producer के आज भेजे गए fields पर चुपचाप निर्भर हो जाएगा। Producer ने एक field हटाया तो onboarding, billing, audit और notification एक साथ टूट सकते हैं।

यह CloudEvents style YAML SaaS user-created event का starting template है। type में domain, fact और version है। idempotencykey duplicate delivery में double side effect रोकता है। correlationid same request से जुड़े logs और traces को जोड़ता है।

specversion: "1.0"
id: "evt_01JZ0YV8Y9N3A7Z7K6Y1G9X2Q4"
type: "com.claudecodelab.user.created.v1"
source: "/services/identity"
subject: "users/usr_123"
time: "2026-06-02T09:30:00Z"
datacontenttype: "application/json"
dataschema: "https://example.com/schemas/user-created.v1.json"
idempotencykey: "user.created:usr_123:2026-06-02"
correlationid: "req_7fc42b"
data:
  userId: "usr_123"
  email: "masa@example.com"
  plan: "starter"
  locale: "hi-IN"

Payload के लिए अलग JSON Schema रखें। Claude Code को implementation देते समय साफ लिखें कि schema के बाहर के fields पर depend न करे, optional field को बिना version bump required न बनाए, और breaking payload change को v2 में ले जाए।

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/schemas/user-created.v1.json",
  "title": "UserCreatedV1",
  "type": "object",
  "additionalProperties": false,
  "required": ["userId", "email", "plan", "locale"],
  "properties": {
    "userId": { "type": "string", "minLength": 1 },
    "email": { "type": "string", "format": "email" },
    "plan": { "type": "string", "enum": ["free", "starter", "pro"] },
    "locale": { "type": "string", "pattern": "^[a-z]{2}-[A-Z]{2}$" }
  }
}

Event names past-tense facts होने चाहिए। user.create या sendEmail command जैसे लगते हैं। user.created, payment.authorized, invoice.finalized facts हैं। user.updated बहुत vague है; email, plan, profile और login time सब उसमें घुस सकते हैं। Important changes को user.email_changed.v1 या subscription.plan_changed.v1 जैसे अलग events में रखें।

Flow diagram से hidden dependency पकड़ें

Implementation से पहले Claude Code से Mermaid diagram बनवाएं। इससे retry, DLQ और hidden synchronous dependency जल्दी दिखती है।

flowchart LR
  A["Identity API<br/>producer"] --> B["Event bus<br/>filter and route"]
  B --> C["Onboarding consumer<br/>workspace setup"]
  B --> D["Email consumer<br/>welcome message"]
  B --> E["Audit consumer<br/>append-only log"]
  C --> F["Idempotency store"]
  D --> F
  C --> G["Dead-letter queue"]
  D --> G
  B --> H["OpenTelemetry<br/>traces metrics logs"]

Review point यह है कि producer सभी consumers के खत्म होने का wait न करे। अगर signup API welcome email भेजे जाने तक response रोकती है, तो system सच में async नहीं है। यह hidden synchronous dependency है। अगर यह product requirement है तो API contract में साफ लिखें; अगर async ठीक है तो UI और recovery को eventual consistency के हिसाब से design करें।

Node.js consumer का copy-paste example

नीचे का consumer user-created event process करता है, onboarding workspace बनाता है, welcome email queue करता है, exact duplicate ignore करता है और failed event को dead-letter queue में डालता है। Example में Map है; production में Redis, DynamoDB, PostgreSQL या shared store इस्तेमाल करें।

const crypto = require("node:crypto");

const processedEvents = new Map();
const deadLetterQueue = [];

function payloadHash(payload) {
  return crypto.createHash("sha256").update(JSON.stringify(payload)).digest("hex");
}

function eventKey(event) {
  return event.idempotencykey || `${event.type}:${event.id}`;
}

function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function withRetry(operation, options = {}) {
  const attempts = options.attempts ?? 3;
  const delayMs = options.delayMs ?? 250;
  let lastError;

  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;
      if (attempt === attempts) break;
      await wait(delayMs * attempt);
    }
  }

  throw lastError;
}

async function handleUserCreated(event, services) {
  if (event.specversion !== "1.0") {
    throw new Error(`Unsupported CloudEvents version: ${event.specversion}`);
  }

  if (event.type !== "com.claudecodelab.user.created.v1") {
    throw new Error(`Unexpected event type: ${event.type}`);
  }

  const key = eventKey(event);
  const currentHash = payloadHash(event.data);
  const existing = processedEvents.get(key);

  if (existing?.status === "succeeded" && existing.payloadHash === currentHash) {
    return { status: "duplicate_ignored", key };
  }

  if (existing && existing.payloadHash !== currentHash) {
    throw new Error("Idempotency key reused with a different payload");
  }

  processedEvents.set(key, {
    status: "processing",
    payloadHash: currentHash,
    updatedAt: new Date().toISOString(),
  });

  try {
    await withRetry(() => services.createOnboardingWorkspace(event.data.userId), {
      attempts: 3,
      delayMs: 200,
    });

    await withRetry(
      () =>
        services.enqueueWelcomeEmail({
          userId: event.data.userId,
          email: event.data.email,
          correlationId: event.correlationid,
        }),
      { attempts: 3, delayMs: 200 },
    );

    processedEvents.set(key, {
      status: "succeeded",
      payloadHash: currentHash,
      updatedAt: new Date().toISOString(),
    });

    return { status: "processed", key };
  } catch (error) {
    processedEvents.set(key, {
      status: "failed",
      payloadHash: currentHash,
      updatedAt: new Date().toISOString(),
      errorMessage: error.message,
    });

    deadLetterQueue.push({
      key,
      event,
      failedAt: new Date().toISOString(),
      errorMessage: error.message,
    });

    throw error;
  }
}

const services = {
  async createOnboardingWorkspace(userId) {
    console.log("workspace ready", { userId });
  },
  async enqueueWelcomeEmail(message) {
    console.log("email queued", {
      userId: message.userId,
      correlationId: message.correlationId,
    });
  },
};

const exampleEvent = {
  specversion: "1.0",
  id: "evt_01JZ0YV8Y9N3A7Z7K6Y1G9X2Q4",
  type: "com.claudecodelab.user.created.v1",
  source: "/services/identity",
  time: "2026-06-02T09:30:00Z",
  idempotencykey: "user.created:usr_123:2026-06-02",
  correlationid: "req_7fc42b",
  data: {
    userId: "usr_123",
    email: "masa@example.com",
    plan: "starter",
    locale: "hi-IN",
  },
};

handleUserCreated(exampleEvent, services)
  .then((result) => console.log(result))
  .catch((error) => console.error(error));

module.exports = { handleUserCreated, withRetry, deadLetterQueue };

Claude Code prompt specific होना चाहिए: successful event फिर से execute न हो, same idempotency key के साथ अलग payload आए तो error हो, transient failure retry हो, और final failure DLQ में रहे। सिर्फ “retry जोड़ दो” कहने से duplicate email या duplicate entitlement बन सकता है।

चार practical use cases

Use caseEventsConsumersRisk
SaaS signup और onboardinguser.created.v1, workspace.created.v1Settings, welcome email, CRM syncSignup API सभी consumers का wait करने लगे
Payment Webhook से fulfillmentpayment.succeeded.v1, subscription.activated.v1Entitlements, invoice, Slack alertSignature verification या idempotency छूट जाए
Audit log और event streamrole.changed.v1, api_key.revoked.v1Append-only log, audit search, SIEMLong-term logs में PII चला जाए
Notification pipelinecomment.mentioned.v1, report.ready.v1Email, in-app, pushPreferences और unsubscribe ignore हो जाए

Payment Webhook event-driven design के लिए अच्छा case है, लेकिन risk high है। Entry point के लिए Webhook implementation with Claude Code देखें। API contract के लिए Production API development with Claude Code उपयोगी है। v1/v2 event migration के लिए API versioning with Claude Code की सोच लागू होती है।

Audit logs में security discipline जरूरी है। Full payload default रूप से log न करें। कौन सा field long retention में रह सकता है, यह तय करने के लिए Claude Code security audit और Claude Code security best practices देखें। Error response और exception shape को error handling patterns से align करें।

Common pitfalls

पहला pitfall vague event name है। user.updated हर consumer को payload पढ़कर फैसला करने पर मजबूर करता है।

दूसरा breaking payload change है। email हटाना, string ID को object बनाना, optional field को required करना independently deployed consumers तोड़ सकता है। Additive changes आमतौर पर safe हैं; delete, type change और meaning change के लिए नई version चाहिए।

तीसरा duplicate delivery भूलना है। कई event systems at-least-once delivery देते हैं, यानी event एक बार तो आएगा, पर कभी-कभी दो बार भी आ सकता है। Email, payment, entitlement और points में idempotency key और durable processed record चाहिए।

चौथा hidden synchronous dependency है। Producer event publish करे और फिर consumer-owned table पढ़कर response दे, तो coupling अभी भी मौजूद है।

पांचवां replay plan न होना है। Consumer bug से तीन घंटे के events fail हों तो retention window, replay filter, duplicate behavior और side-effect suppression पहले से पता होना चाहिए।

छठा observability की कमी है। Logs में event id, type, correlation id, consumer name, retry count और DLQ reason चाहिए। Metrics में backlog age, failure rate, duplicate count और replay count चाहिए।

सातवां PII logging है। PII यानी ऐसी जानकारी जिससे व्यक्ति पहचाना जा सके, जैसे email, name, address, payment detail या token। Logs में full payload न डालें; event id और userId से trace करें।

Claude Code review template

Implementation से पहले review मांगें।

# Claude Code EDA review checklist

Scope:
- event contract: schemas/user-created.v1.json
- producer: services/identity
- consumers: onboarding, email, audit-log

Please review:
- Is the event name a past-tense fact?
- Is the payload change backward compatible for existing consumers?
- Is there an idempotency key, and does duplicate delivery avoid double side effects?
- Does any consumer call back into the producer synchronously?
- Are retry count, backoff, and dead-letter rules explicit?
- Can replay run without duplicate email, payment, or irreversible effects?
- Do logs avoid PII and secrets?
- Can OpenTelemetry show event id, correlation id, and consumer name?

Output:
- P0/P1/P2 risks
- Files that should change
- Tests that should be added
- Open decisions a human must make

अगर Claude Code dangerous assumption पकड़े, तो code लिखने से पहले boundary ठीक करें। फिर schema, handler, tests और runbook के क्रम में implementation कराएं।

Operations runbook

Event-driven system तभी useful है जब failure में operate हो सके। पहला consumer बनाते समय runbook भी रखें।

# Runbook: event backlog or DLQ growth

## Symptoms
- Queue age is over 5 minutes
- Dead-letter queue has more than 10 messages
- Consumer error rate is over 2 percent for 10 minutes

## First checks
1. Identify event type, consumer name, and correlation id.
2. Check whether the failure is validation, downstream timeout, or permission.
3. Confirm whether the producer is still publishing new events.
4. Stop replay if the event triggers email, payment, or irreversible side effects.

## Recovery
1. Fix the consumer or downstream dependency.
2. Replay a small batch with idempotency enabled.
3. Compare processed count, duplicate count, and DLQ count.
4. Resume normal processing.
5. Write the incident note with event ids, time range, and customer impact.

## Never do
- Do not edit payloads manually without recording the reason.
- Do not replay payment or email events without suppression rules.
- Do not paste full payloads with PII into chat or issue trackers.

Merge से पहले Claude Code से पूछें: “इस runbook से कौन सी failure recover नहीं होगी?” इससे missing permission, schema drift या external API assumption जल्दी मिलती है।

Summary और CTA

Event-driven architecture तभी मजबूत बनती है जब event contract को public API की तरह maintain किया जाए। Event names, schema, versioning, idempotency, ordering, retries, dead-letter handling, replay और observability पर explicit decision चाहिए। Claude Code सबसे useful तब है जब वह इन decisions की review करे और clear contract के अनुसार छोटे changes implement करे।

ClaudeCodeLab Claude Code training, event-driven design review, Webhook/API contracts, audit log strategy, incident runbooks और team workflow में मदद कर सकता है। अगर आपकी team Webhooks को safe बनाना चाहती है, notifications को async workers में ले जाना चाहती है या Claude Code review prompts standard करना चाहती है, तो Claude Code training and consulting से शुरू करें। Self-study के लिए free cheat sheet और product templates देखें।

Masa ने इस flow को छोटे SaaS prototype में test किया। जब event contract और idempotency key पहले लिखे गए, Claude Code के changes छोटे और review-friendly रहे। पुराने prototype में केवल user.updated था, इसलिए notification और audit consumers payload details देखकर branching करने लगे और replay unclear रहा। Event names अलग करने और DLQ runbook जोड़ने के बाद यह साफ हो गया कि किस time range से कौन से events replay करने हैं और कितने records expect करने हैं।

#Claude Code #event-driven #architecture #CQRS #design patterns
मुफ़्त

मुफ़्त PDF: Claude Code cheatsheet

Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.

हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.

Masa

लेखक के बारे में

Masa

Claude Code workflow और team adoption पर काम करने वाला engineer.