Thursday, 6 August 2026

IQS

 Q) Order, inventory, and notification. Okay. They are running in a sequence, first order ends, then inventory, and then notification. If inventory fails, you have to roll back the order microservice also. Either all of them will go through or all of them will go back. Yeah. To maintain this type of transaction in microservice endpoint, what strategy or design pattern you will implement and how you will do it?
A) 

Client

   |

Order Service

   |

Inventory Service

   |

Notification Service

Orchestration 

A central Saga Orchestrator controls the entire workflow.


          Client

             |

      Saga Orchestrator

       /      |       \

      /       |        \

 Order   Inventory   Notification


1. Create Order

       ✔


2. Reserve Inventory

       ❌ Failed


3. Orchestrator calls


CancelOrder()


Order status = Cancelled

Azure Implementation

In Azure, a typical implementation is:

  • Order Service → Creates the order.
  • Azure Service Bus → Publishes OrderCreated event.
  • Inventory Service → Consumes the event and reserves stock.
  • If reservation succeeds, it publishes InventoryReserved.
  • If reservation fails, it publishes InventoryReservationFailed.
  • Saga Orchestrator (or Order Service in choreography) consumes the failure event and calls the Order Service to cancel the order.
  • Notification Service is called only after all previous steps succeed.

To maintain transactions across multiple microservices, I would use the Saga Pattern. Each service performs a local transaction and, if a later step fails, executes a compensating transaction instead of a database rollback. In my project, I'd prefer the Orchestration Saga, where a Saga Orchestrator coordinates the workflow. For example, if the Order Service creates an order and the Inventory Service fails to reserve stock, the orchestrator invokes the Order Service's CancelOrder() API to compensate for the earlier step. Communication is typically asynchronous using Azure Service Bus, RabbitMQ, or Kafka. This approach keeps services loosely coupled and is the recommended pattern for distributed transactions in microservices.

I would implement the Saga using the Orchestration approach. I'd create a Saga Orchestrator as a separate service (or a workflow component) that coordinates the process. It first calls the Order Service to create an order with a Pending status. Then it calls the Inventory Service. If inventory reservation succeeds, it proceeds to the Notification Service and finally updates the order to Confirmed. If any service fails, the orchestrator invokes compensating APIs, such as CancelOrder(), to undo the previously completed step. This provides eventual consistency without using distributed database transactions

Step-by-step flow

  1. Client sends a PlaceOrder request.
  2. The Saga Orchestrator calls the Order Service.
  3. Order Service creates the order with status Pending and returns success.
  4. The Saga Orchestrator calls the Inventory Service.
  5. If inventory reservation succeeds, the orchestrator calls the Notification Service.
  6. If all steps succeed, the orchestrator calls the Order Service again to update the order status to Confirmed.

If the Inventory Service fails:

  • The orchestrator immediately calls the Order Service's CancelOrder() endpoint.
  • Order status changes from Pending to Cancelled.
  • Notification Service is not called.
public async Task PlaceOrder(OrderRequest request)
{
    var order = await orderService.CreateOrder(request);

    try
    {
        await inventoryService.ReserveStock(order.Id);
        await notificationService.SendConfirmation(order.Id);

        await orderService.ConfirmOrder(order.Id);
    }
    catch
    {
        await orderService.CancelOrder(order.Id);
        throw;
    }
}

If you're using Amazon SQS (Simple Queue Service), you can explain the orchestration flow like this in an interview.

How it works

  1. The client sends a request to the Saga Orchestrator.
  2. The orchestrator calls the Order Service, which creates the order with a Pending status.
  3. The orchestrator publishes an OrderCreated message to an SQS queue.
  4. The Inventory Service reads the message from SQS and tries to reserve stock.
  5. If successful, it publishes a success message, and the orchestrator proceeds to the Notification Service.
  6. If inventory fails, it sends a failure message to another SQS queue (or a failure event).
  7. The Saga Orchestrator receives the failure message and calls the Order Service's CancelOrder() API as the compensating transaction.
Q) An API or microservice is failing intermittently in production. The same payload sometimes succeeds and sometimes fails. How would you handle it?
A) To handle intermittent failures, I would first identify whether the failure is transient. I'd implement retries with exponential backoff using Polly. If failures continue, I'd use a Circuit Breaker to prevent overloading the downstream service. For asynchronous communication with SQS, failed messages would be retried automatically, and after exceeding the retry limit, they'd be moved to a Dead Letter Queue for later processing. I'd also make the APIs idempotent to avoid duplicate processing and use centralized logging and monitoring with correlation IDs to diagnose production issues. This approach ensures the system is resilient and messages are not lost.

Q) If you are implementing a retry on an API endpoint, what is the effective way of implementing the retry button?
A) I would not implement retries manually with loops. In .NET, the recommended approach is to use Polly with HttpClientFactory. Polly provides configurable retry policies, exponential backoff, jitter, timeout, and circuit breaker support

Example using Polly
services.AddHttpClient<IOrderService, OrderService>()
    .AddPolicyHandler(
        Policy<HttpResponseMessage>
            .Handle<HttpRequestException>()
            .OrResult(r => r.StatusCode == HttpStatusCode.InternalServerError ||
                           r.StatusCode == HttpStatusCode.ServiceUnavailable)
            .WaitAndRetryAsync(
                3,
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
            ));

Q) deployed in the production and we are using Docker to build the image from of your microservice. Now the question is once the image is ready, where you will push that image in the cloud? What is the name of that service which is used to keep and host the Docker image
A) After building the Docker image, we push it to a Container Registry. The registry stores Docker images, and deployment platforms pull images from it.




After building the Docker image in the CI/CD pipeline, we push it to a Container Registry. In Azure, we use Azure Container Registry (ACR). The deployment platform, such as AKS or Azure App Service, pulls the image from ACR and deploys the latest version of the microservice. This keeps image storage secure, versioned, and integrated with the deployment pipeline

Q) SNS vs SQS

FeatureSQS (Simple Queue Service)SNS (Simple Notification Service)
CommunicationPoint-to-PointPublish-Subscribe (Pub/Sub)
Message DeliveryOne consumer processes one messageMultiple subscribers receive the same message
PurposeQueue messages for processingBroadcast messages to multiple services
ProcessingAsynchronousAsynchronous
Message StorageMessages are stored until consumedMessages are not stored for long-term processing by SNS itself
ConsumersUsually one consumer per messageMany subscribers (SQS, Lambda, HTTP endpoints, email, SMS, etc.)












Q) What are the different trigger points for AWS Lambda?

A) AWS Lambda can be triggered by many AWS services. The most common ones are:
  1. API Gateway
    • Triggered when an HTTP/REST API request is received.
    • Example: A client calls /orders, and API Gateway invokes a Lambda function.
  2. Amazon SQS
    • Lambda is triggered when new messages arrive in an SQS queue.
    • Example: Process orders asynchronously from a queue.
  3. Amazon SNS
    • Lambda is triggered when a message is published to an SNS topic.
    • Example: Send notifications or process events.
  4. Amazon S3
    • Triggered when a file is uploaded, deleted, or updated.
    • Example: Resize an uploaded image or process a PDF.
Q) First Lambda function is reading the files from the S3 bucket. Second Lambda function is processing it, and third Lambda function is putting the data into the database. Now, you need to create a design in AWS which can synchronize between each Lambda, and to make sure that each Lambda should run for each and every file in the S3 bucket. Okay. If any failure happens in any Lambda, the previous Lambda has to roll back for that particular file. We need to keep explicitly track of each Lambda and file, what is getting processed, what is not, with monitoring, logging, everything explicitly. So how you will design this solution in AWS?
A) I would implement this using AWS Step Functions to orchestrate the three Lambda functions. An S3 upload event starts the workflow. Step Functions invoke Lambda 1 to read the file, Lambda 2 to process it, and Lambda 3 to save the data to the database. Each Lambda updates a tracking table, such as DynamoDB, with the file name, processing status, current step, and any errors. I would configure retries with exponential backoff for transient failures. If a step still fails, the Step Function executes a compensating action to undo the completed work for that file. For observability, I would use CloudWatch Logs, CloudWatch Metrics, AWS X-Ray, and Step Functions execution history to monitor each file's progress and quickly identify failures. This ensures every file is tracked individually, failures are handled gracefully, and the workflow is fully auditable

Workflow

  1. A file is uploaded to the S3 bucket.
  2. The S3 event triggers the Step Function.
  3. Step Functions invoke Lambda 1 to read the file.
  4. If successful, it invokes Lambda 2 to process the file.
  5. If successful, it invokes Lambda 3 to save the data to the database.
  6. If any Lambda fails, Step Functions execute a Catch block and invoke a compensating Lambda (rollback logic), such as deleting partially inserted records or updating the file status.
Q) Difference between async/await and Multithreading
Async/AwaitMultithreading
Used for I/O-bound operationsUsed for CPU-bound operations
Does not create a new thread by itselfCreates or uses multiple threads
Improves application responsivenessImproves parallel execution
Uses Task and awaitUses Thread, Task.Run(), or the Thread Pool
Ideal for API calls, database calls, file I/OIdeal for heavy calculations, image processing, encryption

Q) Service Lifetimes with Real-Time Examples
A) 

1. Transient (AddTransient)

  • A new instance is created every time it is requested.
  • Best for lightweight, stateless services.

Real-time examples:

  • Email service
  • SMS service
  • PDF generation service
  • Tax calculation service
  • Validation service
builder.Services.AddTransient<IEmailService, EmailService>();

Example:

  • User registration sends an email.
  • Password reset sends another email.
  • Each request gets a new EmailService instance.

2. Scoped (AddScoped)

  • One instance is created per HTTP request.
  • All components within the same request share the same instance.

Real-time examples:

  • DbContext (Entity Framework Core)
  • Repository classes
  • Unit of Work
builder.Services.AddScoped<AppDbContext>();

Example:

  • An API request updates an order.
  • Controller, repository, and service all use the same DbContext instance during that request.

3. Singleton (AddSingleton)

  • Only one instance is created for the entire application lifetime.
  • Shared across all users and requests.

Real-time examples:

  • Cache service
  • Configuration service
  • Logging service
  • Feature flag service
builder.Services.AddSingleton<ICacheService, CacheService>();

Example:

  • A cache stores product data.
  • Every request uses the same cache instance instead of creating a new one.
Q) Authenticate the request, in the B. So B should know that this is coming from A. Okay. Right, how B will come to know that this is coming from A or C? So, you should send something from A so that B came to know that this is coming from A, and based on that, you will authenticate the request and return the results. Yeah, correct. So the question is, what you will send from A to B.
A) API A should send an Access Token (JWT or OAuth 2.0 Bearer Token) to API B. API B validates the token and identifies which service is calling.




Q) We came to know that this is a token which A has requested. It could be the token that C has requested. B, B don't have the user session management. Like, your principal claims are not managed in B. It is only managed in A or C only because B is an external API. Okay, third party like. Right. Then how you will authenticate the service to service calls?
A) Use Service-to-Service Authentication with a Client ID and Client Secret (OAuth 2.0 Client Credentials Flow) or Mutual TLS (mTLS).


How it works

  1. API A authenticates itself using its Client ID and Client Secret.
  2. The Identity Provider (Azure AD, AWS Cognito, Auth0, Okta, etc.) issues an access token.
  3. API A sends that token to API B.
  4. API B validates:
    • Token signature
    • Issuer
    • Audience
    • Client ID (or application identity)

API B doesn't need to know the end user. It only verifies that API A is an authorized client.

Q) Two web application servers, Web application A, web application B. They are hosting an application like MVC or something, and they are working in a distributed. Both are isolated to each other in the form of VPC. There is no connection directly between them, in the form of VPC, APIs. You cannot pass data directly between. Eventually, A has access to SQL Server, B won't have. Now, as soon as you query some data from, select star from manager where employee_id equals 1. That data will be visible in A. But what I want that data should also be visible in B. So, the question is, how you will set up that indirect communication between A and B so that data can be sent in a real time.

A) The expected answer is message-based asynchronous communication.




How it works

  1. User updates data through Application A.
  2. A saves the data in SQL Server.
  3. After a successful commit, A publishes an event such as:
    • ManagerUpdated
    • EmployeeUpdated
  4. The event is sent to a message broker (SQS/SNS, Kafka, RabbitMQ, Azure Service Bus, etc.).
  5. Application B subscribes to the event.
  6. B processes the event and updates its own data store or cache.
  7. Both applications now have consistent data without direct communication.








No comments:

Post a Comment