Thursday, 12 March 2026

how to control duplicate order

 Controlling duplicate orders is a common challenge in distributed systems, APIs, and microservices (especially in .NET Core + Angular + SQL Server architectures like yours). Duplicate orders usually happen due to:

  • User clicking “Place Order” multiple times

  • Network retries from client or gateway

  • Message queue retries

  • Concurrency issues in DB

  • API being called twice

Below are the most effective real-world solutions used in production systems. 🚀


1️⃣ Use Idempotency Key (Best Practice for APIs)

An Idempotency Key ensures that even if the request is sent multiple times, only one order is created.

Flow

  1. Angular generates a unique key (GUID).

  2. Send it in API header.

Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000
  1. API checks database/cache.

  • If key exists → return existing order.

  • If not → create order and store key.

Table Example

CREATE TABLE OrderRequests
(
    IdempotencyKey UNIQUEIDENTIFIER PRIMARY KEY,
    OrderId INT,
    CreatedDate DATETIME
)

.NET Core Example

[HttpPost]
public async Task<IActionResult> CreateOrder([FromHeader(Name="Idempotency-Key")] string key)
{
    var existing = await _db.OrderRequests
        .FirstOrDefaultAsync(x => x.IdempotencyKey == Guid.Parse(key));

    if(existing != null)
        return Ok(existing.OrderId);

    var order = new Order();
    _db.Orders.Add(order);
    await _db.SaveChangesAsync();

    _db.OrderRequests.Add(new OrderRequest
    {
        IdempotencyKey = Guid.Parse(key),
        OrderId = order.Id
    });

    await _db.SaveChangesAsync();

    return Ok(order.Id);
}

✅ Prevents duplicate orders even if API is called 10 times.


2️⃣ Unique Constraint in Database

Use unique index to prevent duplicate order creation.

Example:

CREATE UNIQUE INDEX UX_Order_User_Product
ON Orders(UserId, ProductId, OrderDate)

If duplicate request comes → SQL Server throws error.


3️⃣ Disable Button in Angular UI

Prevent multiple clicks.

isSubmitting = false;

placeOrder() {
  if(this.isSubmitting) return;

  this.isSubmitting = true;

  this.orderService.placeOrder().subscribe({
    next: () => this.isSubmitting = false,
    error: () => this.isSubmitting = false
  });
}

HTML:

<button [disabled]="isSubmitting">
Place Order
</button>

4️⃣ Optimistic Concurrency Control

Use RowVersion / Timestamp column.

ALTER TABLE Orders
ADD RowVersion ROWVERSION

Used when multiple users update same order.


5️⃣ Distributed Lock (Redis / Cache)

In high-traffic systems.

Example:

Lock Key = Order_UserId_ProductId

If lock exists → reject request.

Tools:

  • Redis

  • Azure Cache

  • Distributed Lock library


6️⃣ Message Queue Deduplication (Microservices)

If using Kafka / SQS / RabbitMQ

Use:

  • MessageId

  • DeduplicationId

  • Exactly-once processing

Example AWS SQS:

MessageDeduplicationId

Prevents duplicate message processing.


7️⃣ Pessimistic Locking (SQL Server)

SELECT * 
FROM Orders WITH (UPDLOCK, HOLDLOCK)
WHERE OrderId = @OrderId

Locks row until transaction completes.


8️⃣ Transaction Handling

Use transaction scope to ensure atomic operation.

using(var transaction = await _db.Database.BeginTransactionAsync())
{
   // create order
   // update inventory

   await transaction.CommitAsync();
}

🔥 Real Enterprise Approach (Used in Amazon / Uber)

They combine:

1️⃣ Idempotency key
2️⃣ Unique DB constraint
3️⃣ Distributed lock (Redis)
4️⃣ Retry-safe APIs

This guarantees exactly one order.


🎯 Interview Answer (Short)

Duplicate orders can be prevented using Idempotency Keys, Unique Database Constraints, Distributed Locks, and UI click prevention.
The most reliable solution is Idempotent APIs where each request contains a unique key and the server processes it only once.


✅ If you want, I can also explain 7 real production scenarios where duplicate orders happen in microservices and how companies solve them (very useful for 40–60 LPA architecture interviews).

Sunday, 11 January 2026

Stored Procedure (SP) pagination for a data grid

Implementing Stored Procedure (SP) pagination for a data grid involves retrieving only a specific "page" of data from the database, rather than the entire dataset, which significantly improves performance and reduces network traffic. The modern and most efficient method in SQL Server (2012 and later) is using the OFFSET...FETCH NEXT clause. 
Stored Procedure Implementation (SQL Server)
The stored procedure needs input parameters for the page number, page size, and an ORDER BY clause (which is mandatory for OFFSET...FETCH). It may also include an output parameter for the total record count, which is useful for displaying navigation controls on the front end. 
sql
CREATE OR ALTER PROCEDURE [dbo].[uspGetPagedData]
    @PageNumber INT,
    @PageSize INT,
    @TotalRecords INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    -- Get the total number of records
    SELECT @TotalRecords = COUNT(*) FROM [YourTableName];

    -- Retrieve the specific page of data
    SELECT *
    FROM [YourTableName]
    ORDER BY [YourSortColumn] ASC -- ORDER BY is required for OFFSET/FETCH
    OFFSET (@PageNumber - 1) * @PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY;
END
  • @PageNumber@PageSize: Input parameters to determine which data to retrieve.
  • @TotalRecords: An output parameter to return the total count of records in the table, enabling the UI to calculate the total number of pages.
  • OFFSET (@PageNumber - 1) * @PageSize ROWS: Skips the appropriate number of rows based on the current page and size.
  • FETCH NEXT @PageSize ROWS ONLY: Selects only the number of rows specified by the page size. 

Friday, 9 January 2026

Object Vs var Vs Dynamic Type in C#

 https://www.c-sharpcorner.com/UploadFile/ff2f08/object-vs-var-vs-dynamic-type-in-C-Sharp/


Introduction to object

The object class is the base class for all ohter classes; in other words all derived types are inherited from the object base type. We can assign values of any type to the object type variable (when the value type is converted to an object it is called "boxing" and when the variable type object is converted into any other value type is called "unboxing").

Example

object a = 10;
object b = "This is test string";
object c = a;

//Below is also possible with object type
object k = "jignesh";
k = 10;
C#

Introduction to var keyword

The var keyword was introduced in C# 3.0. It is an implicit type and the type is determined by the C# compiler. There is no performance penalty when using var. The C# compiler assigns types to the variable when it assigns the value.

Example

var a = 10; // it is same as int a = 10;
var b = "This is test string";
var c = b; // gives compilation error.

var words = new string[] { "apple", " banana", "peach", " grape" };
C#

It makes programs shorter and easier to read. In short the var keyword is an implicit way of defining data types. It is an indirect way of defining the variable type. The “var” keyword defines the data type statically (at compile time) and not at runtime.

The var keyword is very useful when.

  1. We have a long class name so that our code is not so readable. var makes it short and sweet.
  2. We use LINQ and anonymous types that help us reduce the code (reduce effort to create a new class).

Introduction to Dynamic Keyword

C# 4.0 introduced a new type called "Dynamic". Dynamic is a new static type that is not known until runtime. At compile time, an element with dynamic is assumed to support any operation so that we need not be worried about the object, whether it get the value from COM, the DOM, from reflection or anything else in the program. Errors are caught at runtime only. The dynamic type in C# uses the Dynamic Language Runtime (DLR) introduced as a new API in the .Net Framework 4.0. Type dynamic behaves like an object in most cases, but the expression of type dynamic is not checked by the compiler. The type's dynamic status is compiled into a variable type object that is dynamic at compile time, not at run time.

At compilation a dynamic is converted into a System.object and the compiler will emit the code for type safety during runtime. It suffers from boxing and unboxing because it is treated as a System.Object and also the application's performance will suffer siince the compiler emits the code for all the type safety.

Example

dynamic i = 10;
dynamic s = "Jignesh Trivedi";

string p = "This is test";
dynamic k = p;

dynamic other = 10; //assign int value so run time type is integer

other = "Jignesh"; // now runtime type of other varible become string.
C#

We can define a dynamic variable, property, field and parameter, return value, type constraint and so on.

// A dynamic field.
static dynamic field;

// A dynamic property.
dynamic name { get; set; }

// A dynamic return type and a dynamic parameter type.
public dynamic Method(dynamic parameter)
{
    dynamic local = "return string";
    int other = 0;

    if (parameter is string)
    {
        return local;
    }
    else
    {
        return other;
    }
}
C#
 ObjectVARDynamic
Introduce in FrameworkC# 1.0C#3.0C#4.0
Stored value typeIt can store any type of value because it is base class i.e. All types in .net framework are derived from object."It can store any type of value, but We must initialize ""var"" types at the time of declaration."It can store any type of value just like old VB language variables.
The compiler has information about the type?Compiler has very little information about the type.It is type safe. It means that the compiler has all information about the type so that there is no issue at run time.It is not type safe. It means that compiler doesn't have any information about the type of variable.
CastingNeed to cast object variable to original type when use it.No need to cast because the compiler has all information about the type.Casting is not required, but we need to know the properties and methods related to stored type because intelligence is not available for dynamic type.
Intellisense support?NoYesNo
Cause the problem at run time?Yes. It throws runtime exception when compiler is not able to convert values from stored value type to required type.No, because type is already known by compiler.Yes. It throws runtime exception When properties or method name are mismatched from original.
UsefulnessIt is very useful when we don't have more information about the type.It is useful when we don't know the actual type.It is very useful when we are using dynamic language for coding or use COM component in our code.
Does it pass to a method or create typed properties?Yes. It can be passed as method parameter and method also can return object type."No, we cannot declare a method parameter or return type as ""VAR""""Yes, we can declare a method parameter or
return type as ""VAR"""

Friday, 19 December 2025

How to Migrate in EF Core Without Data Loss

 This is a very important real-time EF Core question.

Let’s break it down clearly, practically, and safely, exactly how it’s done in production systems.


How to Migrate in EF Core Without Data Loss

(Adding / Removing Columns Safely)


Golden Rule (Interview Answer)

EF Core migrations never delete data unless you explicitly tell them to.
Data loss happens only when:

  • You drop a column/table

  • You change data type incorrectly

  • You don’t provide defaults for non-nullable columns


1️⃣ Adding a Column WITHOUT Data Loss (Safe Way)

Scenario

Existing Users table already has data.
Now you want to add a new column.


✅ Case 1: Add Nullable Column (Safest)

public string PhoneNumber { get; set; }

Migration generated

migrationBuilder.AddColumn<string>(
    name: "PhoneNumber",
    table: "Users",
    nullable: true);

✔️ No data loss
✔️ Existing rows remain untouched

👉 Recommended approach


✅ Case 2: Add Non-Nullable Column (Correct Way)

public bool IsActive { get; set; }

❌ This will fail if table already has rows.

✔️ Correct Solution – Provide Default Value

migrationBuilder.AddColumn<bool>(
    name: "IsActive",
    table: "Users",
    nullable: false,
    defaultValue: true);

✔️ Existing rows get default value
✔️ No data loss


🚫 WRONG WAY

public bool IsActive { get; set; } // no default

❌ Migration fails
❌ Causes runtime exception


2️⃣ Removing a Column WITHOUT Data Loss (Safe Strategy)

Important Truth

Dropping a column ALWAYS deletes data
There is no automatic safe delete.

So how do real projects do it?


✅ Strategy 1: Soft Remove (Recommended)

Instead of deleting column:

public bool IsDeprecated { get; set; }

✔️ Column remains
✔️ App stops using it
✔️ Data preserved


✅ Strategy 2: Two-Step Migration (Production Safe)

Step 1: Backup Data

SELECT OldColumn INTO Users_OldColumn_Backup FROM Users;

Step 2: Drop Column

migrationBuilder.DropColumn(
    name: "OldColumn",
    table: "Users");

✔️ No business data lost
✔️ Recoverable if needed


✅ Strategy 3: Move Data Before Removing Column

migrationBuilder.Sql(
    "UPDATE Users SET NewColumn = OldColumn");

Then drop old column.

✔️ Data preserved
✔️ Schema cleaned


3️⃣ Renaming Column (Common Data Loss Mistake)

❌ Wrong Way

public string MobileNumber { get; set; } // renamed from PhoneNumber

EF Core thinks:

  • Drop PhoneNumber

  • Add MobileNumber

➡️ ❌ DATA LOSS


✅ Correct Way – Rename Column

migrationBuilder.RenameColumn(
    name: "PhoneNumber",
    table: "Users",
    newName: "MobileNumber");

✔️ Data retained
✔️ Safe migration


4️⃣ Changing Column Data Type (Safely)

❌ Risky

public int Age { get; set; } // previously string

✅ Safe Migration

migrationBuilder.Sql(
    "UPDATE Users SET Age = TRY_CAST(Age AS INT)");

Then change column type.

✔️ Converts data
✔️ Prevents failure


5️⃣ Best Practices to Avoid Data Loss (Real-World)

✔️ Always review migration script

dotnet ef migrations script

✔️ Take DB backup before prod migration

✔️ Never use EnsureCreated() in prod

✔️ Avoid auto-migrate on app startup

✔️ Use feature-based migrations


6️⃣ Real Interview Answer (Concise)

To migrate without data loss in EF Core, we add nullable or default-valued columns, rename columns using RenameColumn, migrate data using SQL before dropping columns, and never delete schema elements directly in production without backup.


7️⃣ Quick Safety Checklist

OperationSafe?How
Add columnNullable or default
Rename columnRenameColumn
Remove columnBackup or soft delete
Change type⚠️Data conversion SQL
Drop tableArchive first

If you want next:

  • 🔥 Zero-downtime production migration

  • 🔥 Blue-green DB migration strategy

  • 🔥 EF Core migration rollback

  • 🔥 Handling huge tables (millions of rows)

  • 🔥 Migration interview questions

Just say the word 👍

Entity Framework core code first migration steps in detailed with example

 Below is a very detailed, step-by-step explanation of EF Core Code-First migrations with a complete real-time example, exactly how it’s expected in enterprise projects and interviews.


EF Core Code-First Migration – Detailed Steps with Example


What is Code-First in EF Core?

Code-First means:

  • You design C# entities first

  • EF Core generates the database schema

  • Migrations track schema changes over time

Database = output
C# code = source of truth


Real-Time Scenario

We are building a User Management API.

Initial Requirements

  • Create Users table

  • Later add Email, DateOfBirth, IsActive


Step 1: Create Web API Project

dotnet new webapi -n UserManagement.API
cd UserManagement.API

Step 2: Install Required Packages

dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

📌 Tools is mandatory for migrations


Step 3: Create Entity Classes (Models)

📁 Entities/User.cs

using System.ComponentModel.DataAnnotations;

public class User
{
    [Key]
    public int Id { get; set; }

    [Required]
    [MaxLength(100)]
    public string Name { get; set; }

    [MaxLength(200)]
    public string Email { get; set; }

    public DateTime DateOfBirth { get; set; }

    public bool IsActive { get; set; }
}

Step 4: Create DbContext

📁 Data/AppDbContext.cs

using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .Property(x => x.IsActive)
            .HasDefaultValue(true);
    }
}

Step 5: Configure Connection String

📁 appsettings.json

"ConnectionStrings": {
  "DefaultConnection": "Server=.;Database=UserManagementDb;Trusted_Connection=True;TrustServerCertificate=True"
}

Step 6: Register DbContext (Program.cs)

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

Step 7: Add Initial Migration

dotnet ef migrations add InitialCreate

What EF Core Does

✔️ Scans entity classes
✔️ Compares model vs empty database
✔️ Generates migration files


Generated Migration (Simplified)

📁 Migrations/xxxx_InitialCreate.cs

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "Users",
        columns: table => new
        {
            Id = table.Column<int>(nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            Name = table.Column<string>(maxLength: 100, nullable: false),
            Email = table.Column<string>(maxLength: 200, nullable: true),
            DateOfBirth = table.Column<DateTime>(nullable: false),
            IsActive = table.Column<bool>(nullable: false, defaultValue: true)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Users", x => x.Id);
        });
}

Step 8: Apply Migration to Database

dotnet ef database update

✔️ Database created
✔️ Tables created
✔️ __EFMigrationsHistory table created


Step 9: Change Entity (New Business Requirement)

Add PhoneNumber field.

📁 User.cs

[MaxLength(15)]
public string PhoneNumber { get; set; }

Step 10: Create New Migration

dotnet ef migrations add AddPhoneNumberToUser

Generated Migration

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn<string>(
        name: "PhoneNumber",
        table: "Users",
        maxLength: 15,
        nullable: true);
}

protected override void Down(MigrationBuilder migrationBuilder)
{
    migrationBuilder.DropColumn(
        name: "PhoneNumber",
        table: "Users");
}

Step 11: Update Database Again

dotnet ef database update

✔️ Schema updated
✔️ Existing data preserved


Step 12: Verify Database

Tables:

  • Users

  • __EFMigrationsHistory


Step 13: Rollback a Migration (If Needed)

dotnet ef database update InitialCreate

or

dotnet ef database update 0

Step 14: Remove Last Migration (Not Applied)

dotnet ef migrations remove

📌 Only works if migration not applied


Step 15: Common EF Core Migration Commands

dotnet ef migrations list
dotnet ef migrations script
dotnet ef database update
dotnet ef migrations remove

Step 16: Data Seeding (Optional)

modelBuilder.Entity<User>().HasData(
    new User { Id = 1, Name = "Admin", Email = "admin@test.com", IsActive = true }
);

Then:

dotnet ef migrations add SeedUsers
dotnet ef database update

Real-Time Best Practices

✔️ One migration per feature
✔️ Never edit applied migrations
✔️ Avoid auto-migrate in production
✔️ Review generated SQL
✔️ Always keep migrations in Git


Common Interview Questions

Q: Difference between EnsureCreated() and migrations?
➡️ EnsureCreated() skips migrations – NOT for production

Q: Where migration history stored?
➡️ __EFMigrationsHistory


One-Line Interview Summary

EF Core Code-First migration allows developers to evolve database schema incrementally using C# models while maintaining version control and data safety.


If you want, I can next explain:

  • 🔥 How EF Core tracks model changes internally

  • 🔥 Multiple DbContext migrations

  • 🔥 Zero-downtime production migrations

  • 🔥 Handling breaking changes

  • 🔥 EF Core migration interview Q&A

Just tell me 👍



PLease describe in detailed with example in .net core if one of the microservice failed then how to rollback the tansaction in orchestrator saga pattern

 Below is a step-by-step, real-world explanation of Orchestrator Saga Pattern with rollback using .NET Core, exactly the way it is implemented in production systems and expected in senior interviews.


🔷 Problem Statement

You have multiple microservices, each with its own database.

Scenario:
Order → Payment → Inventory → Shipping

👉 If any service fails, you must rollback previously completed steps.

❌ You cannot use DB transactions across services
✅ You must use Saga + Compensating Transactions


🔷 What Is Orchestrator Saga Pattern?

A central Saga Orchestrator controls:

  • The order of service calls

  • Success/failure handling

  • Compensation (rollback) logic

The orchestrator does NOT share DBs
It only invokes APIs / publishes commands


🔷 High-Level Flow Diagram

Client
  |
  v
Saga Orchestrator
  |
  |---> Order Service (Create Order)
  |---> Payment Service (Charge)
  |---> Inventory Service (Reserve)
  |---> Shipping Service (Create Shipment)

Failure Example

❌ Inventory fails → Orchestrator:

  • Refund Payment

  • Cancel Order


🔷 Step-by-Step Implementation in .NET Core


1️⃣ Order Service (Local Transaction)

Order Entity

public class Order
{
    public Guid Id { get; set; }
    public string Status { get; set; } // Pending, Confirmed, Cancelled
}

Order Controller

[HttpPost("create")]
public async Task<IActionResult> CreateOrder()
{
    var order = new Order { Id = Guid.NewGuid(), Status = "Pending" };
    _db.Orders.Add(order);
    await _db.SaveChangesAsync();
    return Ok(order.Id);
}

[HttpPost("cancel/{orderId}")]
public async Task<IActionResult> CancelOrder(Guid orderId)
{
    var order = await _db.Orders.FindAsync(orderId);
    order.Status = "Cancelled";
    await _db.SaveChangesAsync();
    return Ok();
}

2️⃣ Payment Service

[HttpPost("charge")]
public async Task<IActionResult> Charge(Guid orderId)
{
    // Simulate payment
    if (Random.Shared.Next(1, 10) < 3)
        return BadRequest("Payment Failed");

    _db.Payments.Add(new Payment { OrderId = orderId, Status = "Paid" });
    await _db.SaveChangesAsync();
    return Ok();
}

[HttpPost("refund")]
public async Task<IActionResult> Refund(Guid orderId)
{
    var payment = await _db.Payments.FirstAsync(p => p.OrderId == orderId);
    payment.Status = "Refunded";
    await _db.SaveChangesAsync();
    return Ok();
}

3️⃣ Inventory Service

[HttpPost("reserve")]
public async Task<IActionResult> Reserve(Guid orderId)
{
    // Simulate failure
    throw new Exception("Inventory not available");
}

4️⃣ Saga Orchestrator (Core Logic)

Orchestrator Controller

[HttpPost("place-order")]
public async Task<IActionResult> PlaceOrder()
{
    Guid orderId = Guid.Empty;

    try
    {
        // 1. Create Order
        orderId = await _orderClient.CreateOrder();

        // 2. Payment
        await _paymentClient.Charge(orderId);

        // 3. Inventory
        await _inventoryClient.Reserve(orderId);

        // 4. Shipping
        await _shippingClient.Create(orderId);

        return Ok("Order Completed");
    }
    catch (Exception ex)
    {
        await Compensate(orderId);
        return StatusCode(500, ex.Message);
    }
}

5️⃣ Compensation Logic (ROLLBACK)

private async Task Compensate(Guid orderId)
{
    if (orderId == Guid.Empty) return;

    try
    {
        await _paymentClient.Refund(orderId);
    }
    catch { /* log */ }

    try
    {
        await _orderClient.CancelOrder(orderId);
    }
    catch { /* log */ }
}

👉 Each compensation is its own API call
👉 Each service performs local DB rollback


🔷 Important Production Considerations ⭐


1️⃣ Idempotency (VERY IMPORTANT)

Compensation might be called multiple times.

if (payment.Status == "Refunded")
    return Ok();

2️⃣ Retry with Polly

Transient failures happen.

Policy
  .Handle<HttpRequestException>()
  .WaitAndRetryAsync(3, retry => TimeSpan.FromSeconds(2));

3️⃣ Timeout & Circuit Breaker

Avoid hanging orchestrator.

.TimeoutAsync(TimeSpan.FromSeconds(5))
.CircuitBreakerAsync(3, TimeSpan.FromMinutes(1));

4️⃣ Saga State Table (Recommended)

SagaState
{
    SagaId,
    OrderId,
    StepCompleted,
    Status
}

So recovery can happen after crash.


5️⃣ Event-Based Orchestrator (Better Scalability)

Instead of HTTP:

  • Azure Service Bus

  • Kafka

  • RabbitMQ


🔷 Why This Works

  • No distributed transaction

  • Each service owns its data

  • Rollback via compensating transactions

  • Eventual consistency


🔷 Interview-Ready Answer (Short)

“In orchestrator saga pattern, a central service controls the workflow. Each microservice performs a local transaction. If any service fails, the orchestrator triggers compensating transactions—like refunding payment or canceling the order—to logically rollback the system and achieve eventual consistency.”


🔷 When to Use Orchestrator Saga

ScenarioUse
Complex workflows
Payment flows
High observability needed
Simple async flows

If you want next, I can explain:

  • Event-driven saga using Kafka/Azure Service Bus

  • Saga persistence & recovery

  • Real production pitfalls

  • Comparison with choreography saga

Just tell me 👍

Wednesday, 17 December 2025

Promise vs Observable

 



console.log('start');

Promise.resolve().then(() => console.log('promise'));

console.log('end');
    const promise = new Promise((resolve,reject)=>{
      console.log("Promise executed");
      resolve(100);
      resolve(200);
      resolve(300);
    });

    promise.then((val)=>{
  console.log("Promise value: ", val);
 });
    const testobs = new Observable(sub=>{
      console.log("Observable executed");
      sub.next(200);
      sub.next(300);
      sub.next(400);
      sub.complete();
    });

    testobs.subscribe((val)=>{
      console.log("Observable value: ", val);
    });

Thursday, 11 December 2025

circuit breaker pattern in .net core

 Below is a clear, interview-ready and practical explanation of the Circuit Breaker pattern in .NET Core, along with real-time examples and code using Polly (the standard library for resilience in .NET).


Circuit Breaker Pattern in .NET Core

What it is

Circuit Breaker is a resilience pattern used to prevent your system from repeatedly calling a failing external service (API/database/message broker).
It protects the system from cascading failures.


🔌 States of Circuit Breaker

State Meaning
Closed Everything works normally (calls allowed).
Open Calls blocked immediately because external service is failing.
Half-Open Allows limited trial calls to see if the service recovered.

⭐ Why we use it

  • To avoid hitting a failing service over & over

  • To prevent resource consumption (threads, CPU, DB connections)

  • To improve latency by quickly failing requests

  • To give time for the external system to recover


📦 Circuit Breaker in .NET Core using Polly

Install package:

dotnet add package Polly.Extensions.Http

✔️ Simple Circuit Breaker Example

services.AddHttpClient("StockApiClient")
    .AddTransientHttpErrorPolicy(policy => 
        policy.CircuitBreakerAsync(
            handledEventsAllowedBeforeBreaking: 3,      // After 3 failures
            durationOfBreak: TimeSpan.FromSeconds(30),  // Keep circuit open for 30 sec
            onBreak: (result, ts) =>
            {
                Console.WriteLine("Circuit opened!");
            },
            onReset: () =>
            {
                Console.WriteLine("Circuit closed!");
            },
            onHalfOpen: () =>
            {
                Console.WriteLine("Circuit half-open: trying test call.");
            }
        ));

Meaning:

  • If API fails 3 times → Circuit goes OPEN

  • For the next 30 seconds → all calls fail immediately

  • After 30 sec → Circuit goes HALF-OPEN

  • If next call succeeds → RESET (Closed)

  • If fails → OPEN again


✔️ Circuit Breaker + Retry (Best Practice)

services.AddHttpClient("PaymentService")
    .AddPolicyHandler(
        HttpPolicyExtensions
            .HandleTransientHttpError()
            .RetryAsync(3) // retry 3 times
    )
    .AddPolicyHandler(
        HttpPolicyExtensions
            .HandleTransientHttpError()
            .CircuitBreakerAsync(5, TimeSpan.FromSeconds(20))
    );

Retry handles intermittent failures.
Circuit Breaker handles persistent failures.


✔️ Using Circuit Breaker in Controller

public class StockController : ControllerBase
{
    private readonly IHttpClientFactory _factory;
    public StockController(IHttpClientFactory factory) => _factory = factory;

    [HttpGet("price/{symbol}")]
    public async Task<IActionResult> GetStockPrice(string symbol)
    {
        var client = _factory.CreateClient("StockApiClient");

        var response = await client.GetAsync($"/api/stock/{symbol}");

        if (!response.IsSuccessStatusCode)
            return StatusCode((int)response.StatusCode, "External service failed");

        var data = await response.Content.ReadAsStringAsync();
        return Ok(data);
    }
}

🎯 Real-Time Scenarios Where You Use Circuit Breaker

1. Payment Gateways

If Razorpay/Stripe API is failing, don’t call them continuously.
Circuit stops the calls.

2. Microservices Architecture

If Order Service relies on Inventory Service and Inventory is down →
stop hammering it; return fallback immediately.

3. Slow database or cache

If Redis/Azure SQL is timing out → circuit opens → API returns quick response instead of long delays.

4. Third-party APIs (SMS, Email, Notification)

Avoid getting throttled or blocked by calling continuously.


📘 How You Answer in Interviews (30-second answer)

“Circuit Breaker is a resilience pattern that prevents the system from making calls to a failing external service.
In .NET Core, we implement it using Polly.
After a defined number of failures, the circuit moves to Open state and blocks all calls for a specified time.
This prevents cascading failures and improves performance.
I generally combine Retry + Circuit Breaker in HttpClient when calling microservices or external systems.”



How to Determine User Story Complexity

 Here is a clear, practical and interview-ready explanation for how to determine User Story complexity.

This is one of the most commonly asked Agile/Scrum questions.


How to Determine User Story Complexity

User Story complexity is measured by evaluating three major dimensions:

⭐ 1. Business Complexity

⭐ 2. Technical Complexity

⭐ 3. Testing / Integration Complexity

These dimensions help the team decide how “big” or “complex” the story is, which drives the story points.


🔍 1. Business Complexity

Ask these questions:

✔ Does the story involve multiple business rules?

Example:

  • Tax calculation

  • Trading validations

  • Loan approval logic

✔ How many scenarios or edge cases exist?

More scenarios → more complexity → more points.

✔ Any conditional/branching workflows?

E.g.,

  • "If order > 50K then approval flow; else auto-approve."

➡ More rules = higher complexity.


🔧 2. Technical Complexity

This is the most important factor for developers.

✔ How complex is the architecture impact?

  • Does it touch multiple layers (UI + API + DB)?

  • Requires new database tables?

  • New microservice integration?

✔ Does it involve new technology or unknowns?

  • First time integrating Kafka

  • New cloud service

  • New OAuth-based authentication

👉 Unknowns always increase complexity because of R&D time.

✔ Inter-service communication complexity

  • Async event driven?

  • REST + retry logic?

  • Multiple microservices involved?

✔ Data transformation level

  • Simple JSON

  • Heavy mapping

  • File parsing (Excel, XML, CSV)

More transformation = more complexity.


🔬 3. Testing / Integration / Deployment Complexity

Even if development is simple, testing can raise complexity.

✔ How many test cases?

  • Simple CRUD → Few test cases

  • Workflow system → Many test cases

✔ Any dependency on external systems?

  • Payment gateway

  • Market data provider

  • Third-party APIs

  • External trading FIX engine

External dependencies → delays → more complexity.

✔ Performance concerns

  • High-volume order ingestion

  • Big file upload

  • Realtime latency-sensitive API

Performance testing = increased complexity.

✔ Deployment complexity

  • Requires config changes

  • Feature flags

  • Release dependency between teams


🧩 Putting It All Together (Complexity Formula)

Complexity =

Business rules + Technical effort + Risks/Unknowns + Testing load + External dependencies

High in any category → high story point.


🟦 Real Project Example (Trading App)

Story:

“Add validation: Reject order if price deviates more than 3% from LTP.”

Complexity evaluation:

Factor Details Complexity
Business Simple rule (1 rule) Low
Technical Need LTP from Market Data microservice Medium
External Dependency on real-time market feed High
Testing Multiple test cases for boundary price Medium

👉 Final story point: 5 or 8 (due to dependency + testing complexity)


🟩 Rule of Thumb for Complexity (Quick cheat sheet)

Complexity Level Indicators Story Points
Low Simple CRUD, small UI change, 1–2 acceptance criteria 1–3
Medium Logic, integration with DB, 4–6 AC, validations 5–8
High Multiple systems, complex logic, unknowns, performance, >6 AC 8–13
Very High (Too big) Many modules, multi-sprint, heavy R&D 20+ → Split

🎤 30-second Interview Answer

“To determine user story complexity, we evaluate three things: business complexity, technical complexity, and testing/integration effort. We check how many business rules are involved, how many systems are impacted, whether any new technology or unknowns exist, and how many test cases or dependencies are involved. Based on these factors, we assign relative story points using Fibonacci. Higher dependencies, unknowns, or multi-layer impacts mean higher complexity.”


Here is a ready-to-use, professional User Story Complexity Checklist that you can directly use in interviews, projects, or sprint refinements.


USER STORY COMPLEXITY CHECKLIST

Use this checklist during backlog refinement to determine whether a story is Low / Medium / High complexity.


🔵 1. Business Complexity

Check all applicable items:

✔ Requirements

  • Story has simple requirements (1–2 rules)

  • Story has multiple business rules

  • Story has conditional workflows

  • Story impacts business-critical flow (e.g., orders, payments)

✔ Acceptance Criteria

  • AC count < 3

  • AC count between 3–6

  • AC count > 6 (complex)

✔ Edge Cases

  • Minimal edge cases

  • Many edge cases (boundary validations, alternate flows)


🟠 2. Technical Complexity

Evaluate the technical effort:

✔ Development Effort

  • Only UI / Only API / Only DB

  • UI + API + DB together

  • Touches multiple microservices

  • Requires refactoring or modifying existing architecture

  • Requires new API / new endpoint

  • Requires new DB table, migration, or schema changes

  • Requires file parsing (Excel, CSV, XML)

  • Involves heavy transformations

✔ Unknowns / R&D

  • No unknowns

  • Some unknowns (new flow)

  • Many unknowns (new technology, new system)

✔ Performance

  • No performance concerns

  • Medium performance impact

  • Large volume / low-latency requirement


🟣 3. Integration Complexity

Check how many external systems are involved:

  • No external system

  • 1 internal system

  • Multiple internal systems

  • Third-party API dependency

  • Asynchronous event/message queue involved (Kafka/SQS/Event Grid)

  • Dependency on external vendor (Market data, Payment gateway)

Integration increases complexity significantly.


🟢 4. Testing Complexity

Testing complexity directly impacts story points.

✔ Test Case Volume

  • < 5 test cases

  • 5–15 test cases

  • > 15 test cases

✔ Testing Types

  • Unit tests only

  • API automation

  • UI automation

  • Performance / load testing

  • End-to-end with multiple systems


🟤 5. Deployment / Release Complexity

Check deployment effort:

  • No deployment changes

  • Config change required

  • Feature flag required

  • Coordinated release with other teams

  • Blue-green / canary deployment impact

  • Downtime or migration impact


🚦 Complexity Scoring Guide

Use this simple rule:

Low Complexity (1–3 Points)

  • Only one layer (UI OR API OR DB)

  • Minimal logic

  • No dependency

  • < 3 AC

Medium Complexity (5–8 Points)

  • Multiple layers (UI + API + DB)

  • Some business logic

  • 3–6 AC

  • One integration

High Complexity (8–13 Points)

  • Multiple microservices

  • Heavy business rules

  • Performance concerns

  • External dependencies

  • 6 AC + many test cases

Too Big – Split the Story

  • Impacts multiple epics

  • Multi-sprint work

  • Many unknowns


📝 Final Output Template (You Can Use in Meetings)

User Story Complexity Summary

  • Business Complexity: Low / Medium / High

  • Technical Complexity: Low / Medium / High

  • Integration Complexity: Low / Medium / High

  • Testing Complexity: Low / Medium / High

  • Deployment Complexity: Low / Medium / High

Overall Story Complexity → LOW / MEDIUM / HIGH (1–3 / 5–8 / 8–13 points)


If you'd like, I can also generate:
📌 A one-page PDF of this checklist
📌 A Excel sheet template for your team
📌 A checklist version for Trading, Banking, or E-commerce domains

Recent Post

how to control duplicate order