Skip to content

Instantly share code, notes, and snippets.

@sauravexodus
Last active October 27, 2025 18:33
Show Gist options
  • Select an option

  • Save sauravexodus/0fbdfd92c58033ed3e605d1260ee4516 to your computer and use it in GitHub Desktop.

Select an option

Save sauravexodus/0fbdfd92c58033ed3e605d1260ee4516 to your computer and use it in GitHub Desktop.
Tests for API throughput maximizer

Yuna Technical Interview Task: High-Throughput Service Client Manager

Overview

Your task is to implement a high-performance ClientManager in Go. This manager is responsible for routing job requests to a critical, external service that enforces extremely strict and non-negotiable operational limits. The primary goal is to maximize throughput and job completion by queueing requests when limits are exceeded, ensuring no job is ever dropped unnecessarily.

The External Service Constraints

The external service imposes two separate, hard limits that must be respected simultaneously:

  1. Concurrency Limit: A maximum of 10 concurrent requests may be active at any given time.

  2. Rate Limit: A maximum of 100 total requests may be made within any 60-second window.

Task Implementation Details

  1. Implement the ClientManager: Create a struct ClientManager that manages the job queue, concurrency pool, and rate limiter. It must expose a non-blocking SubmitJob(job Job) error method. If the internal job queue is full, the submission should apply backpressure and block the caller until space is available in the internal queue.

  2. The External Service (Mock): You must implement a mock function/method representing the actual API call:

    // This function simulates the latency of the external API call.
    func ExternalServiceCall(job Job) error {
        // Simulate network latency (e.g., 50ms - 500ms)
        delay := time.Duration(rand.Intn(450) + 50) * time.Millisecond
        time.Sleep(delay)
    
        // 1% chance of a transient failure
        if rand.Intn(100) == 0 {
            return fmt.Errorf("transient service error for job %s", job.ID)
        }
    
        // Simulate successful completion
        return nil
    }
    
    
  3. Job Structure: Define a simple Job struct.

    type Job struct {
        ID string
        UserID string // Mandatory for user-level quota tracking
        // Add other relevant fields if you like, e.g., Payload...
    }
    
    
  4. Testing and Demonstration: Include a main function that demonstrates submitting at least 500 jobs concurrently and prints logs showing successful execution, adherence to constraints, and handling of errors.

Example Scenarios (Expected Behavior)

To better illustrate the requirements, consider these scenarios:

Scenario Action Expected Manager Behavior
High Concurrency 20 jobs submitted immediately. 10 jobs start execution. The remaining 10 jobs are held in the internal queue, starting only as the initial 10 complete.
Rate Limit Hit 100 requests executed in 10 seconds. The 101st request is immediately queued. It must wait until the 60-second time window is reset (i.e., 50 seconds later) before it can begin processing, regardless of concurrency slots being open.
Graceful Shutdown Call the shutdown method while 5 jobs are running and 15 are queued. The 5 running jobs finish. The 15 queued jobs are then processed and completed before the manager truly exits.

Success Criteria (5 Core Requirements)

The solution must:

  1. Concurrency Management: Correctly implement a worker pool or semaphore structure ensuring that no more than 10 goroutines are executing ExternalServiceCall simultaneously.

  2. Request Queuing/Backpressure: Implement an internal mechanism to queue submitted jobs using a First-In, First-Out (FIFO) order when limits are exceeded. Jobs must never be failed or dropped due to temporary backpressure.

  3. Rate Limiting Precision: Employ a rate limiting mechanism that strictly enforces the limit of 100 requests per 60 seconds on a rolling basis, serving queued requests immediately when a new window opens.

  4. Graceful Shutdown: Implement a mechanism (e.g., a context or a dedicated method) to shut down the ClientManager gracefully, ensuring all submitted and queued jobs are processed and completed before termination.

  5. Efficiency and Throughput: The design should prioritize maximum achievable throughput, minimizing unnecessary idling. The manager should process queued jobs immediately whenever both concurrency and rate limit resources become available.

Bonus Points (3 Additional Challenges)

  1. Retry Logic: Implement an exponential backoff and retry mechanism for jobs that fail with a transient error (the 1% failure case), with a maximum of 3 retries per job.

  2. Dynamic Configuration: Refactor the ClientManager initialization to accept the concurrency limit (N) and rate limit (R requests / T seconds) as parameters, allowing it to be configured dynamically.

  3. Hierarchical Quota Tracking (System and User Level):

    • Allow the ClientManager to be initialized with two quota limits:

      • System-Level Quota: A maximum number of total requests allowed for all users combined (e.g., 100,000 per 24 hours).

      • User-Level Quota: A maximum number of requests allowed per unique UserID (e.g., 5,000 per 24 hours).

    • The manager must enforce both limits simultaneously. A job must be stopped if either the System-Level or its specific User-Level quota is exceeded.

    • Implement a dedicated method to reset these long-term quotas.

Sample Test Cases

These five tests should be implemented in the candidate's solution to prove all core requirements are met:

  1. Test Concurrency Limit and FIFO Order:

    • Action: Submit 15 unique jobs immediately. Jobs 1-15 all have the same UserID.

    • Assertion: Jobs 1-10 start concurrently. Jobs 11-15 are queued. Jobs 11-15 must start in order (11, then 12, then 13, etc.) as the initial 10 jobs complete.

  2. Test Rolling Rate Limit (The Delay Test):

    • Setup: Ensure the ExternalServiceCall mock is fast (e.g., 5ms latency).

    • Action: Submit 101 jobs very quickly (within 1 second).

    • Assertion: Jobs 1-100 execute. Job 101 must be successfully submitted but must not start execution until at least 60 seconds have elapsed since Job 1 started.

  3. Test Mixed Limit Saturation:

    • Action: Submit 50 jobs. The first 10 immediately fill the Concurrency Limit. As the first 10 finish, submit 60 more jobs (total 110 jobs submitted within 10 seconds).

    • Assertion: 100 jobs execute within the first 60 seconds. Jobs 101-110 are successfully queued and must remain queued until the rate limit window for the first request expires.

  4. Test Graceful Shutdown and Completion:

    • Action: Submit 50 jobs. After 5 jobs start running, immediately call the Shutdown() method.

    • Assertion: The Shutdown() call must block until all 50 submitted jobs (running and queued) have completed execution successfully. No jobs should be dropped.

  5. Test Hierarchical Quota Enforcement (Bonus 3 Required):

    • Setup: Initialize the manager with a System Quota of 50 and a User Quota of 10.

    • Action: Submit 15 jobs for UserID=A and 15 jobs for UserID=B.

    • Assertion:

      • UserID=A processes 10 jobs and hits the User Quota.

      • UserID=B processes 15 jobs.

      • The System-Level Quota (50) is reached. Subsequent jobs for any user must be permanently rejected/failed with a "Quota Exceeded" error.

package main
import (
"fmt"
"math/rand"
"sync"
"testing"
"time"
)
// --- Task Definitions (Required by the Manager) ---
// Job represents a single request to the external service.
type Job struct {
ID string
UserID string // Mandatory for user-level quota tracking
}
// ExternalServiceCall simulates the external API's latency and transient failures.
// NOTE: In the final solution, the ClientManager should call this function.
func ExternalServiceCall(job Job) error {
// Simulate network latency (e.g., 50ms - 500ms)
delay := time.Duration(rand.Intn(450)+50) * time.Millisecond
time.Sleep(delay)
// 1% chance of a transient failure
if rand.Intn(100) == 0 {
return fmt.Errorf("transient service error for job %s", job.ID)
}
return nil
}
// --- ClientManager Skeleton (Candidate's implementation target) ---
// Config holds dynamic and quota limits (related to Bonus 2 & 3).
type Config struct {
ConcurrencyLimit int
RateLimit int
RateWindow time.Duration
SystemQuota int
UserQuota int
}
// ClientManager is the structure the candidate must implement.
type ClientManager struct {
cfg Config
// Internal fields for concurrency, rate limiting, queuing, etc.
}
// NewClientManager initializes and starts the background workers for the manager.
func NewClientManager(cfg Config) *ClientManager {
// Candidate's implementation logic goes here
return &ClientManager{cfg: cfg}
}
// SubmitJob adds a job to the manager's queue. Must block if the internal queue is full.
func (cm *ClientManager) SubmitJob(job Job) error {
// Placeholder: In a real test, this would submit to the CM's queue.
// We skip here as the purpose is only to test the CM's behavior.
return nil
}
// Shutdown gracefully waits for all submitted and queued jobs to complete.
func (cm *ClientManager) Shutdown() {
// Placeholder: In a real test, this would wait on a WaitGroup or similar.
}
// --- Sample Test Cases (Candidate must ensure their implementation passes these) ---
func TestConcurrencyAndFIFO(t *testing.T) {
const (
concurrencyLimit = 10
totalJobs = 15
testUserID = "user-A"
)
// The candidate must configure their manager to use the default 10 concurrency limit.
manager := NewClientManager(Config{ConcurrencyLimit: concurrencyLimit})
defer manager.Shutdown()
var wg sync.WaitGroup
startTimes := make(map[string]time.Time)
var mu sync.Mutex // Mutex to protect startTimes map
// 1. Mock ExternalServiceCall to allow us to observe concurrency
// In a real test, the manager would internally call the mock, and the test would
// monitor the *number of simultaneous goroutines* executing that call.
// For this test skeleton, we'll focus on submission order and timing.
t.Logf("Submitting %d jobs to test concurrency limit of %d and FIFO order...", totalJobs, concurrencyLimit)
for i := 1; i <= totalJobs; i++ {
wg.Add(1)
job := Job{ID: fmt.Sprintf("Job-%d", i), UserID: testUserID}
go func(j Job) {
defer wg.Done()
// Submit the job to the manager (which queues it internally)
if err := manager.SubmitJob(j); err != nil {
t.Errorf("SubmitJob failed for %s: %v", j.ID, err)
return
}
// When the job is dequeued and starts execution by the manager:
mu.Lock()
startTimes[j.ID] = time.Now()
mu.Unlock()
// The candidate's internal manager logic must ensure this call respects
// both concurrency and rate limits.
// ExternalServiceCall(j) // The actual work happens here
time.Sleep(100 * time.Millisecond) // Simplified placeholder for work
t.Logf("Job %s completed.", j.ID)
}(job)
}
wg.Wait()
t.Log("All jobs submitted and processed.")
// Assertion 1: Concurrency (Jobs 1-10 should start roughly at the same time)
// Due to the difficulty of testing true concurrency without controlling the manager's internals,
// we will focus on the FIFO queuing aspect, which is a required criteria.
// Assertion 2: FIFO Order (Jobs 11-15 must start in order)
// If the manager uses a proper FIFO queue, the start times should be sequential.
// The start time of Job 11 should be shortly after the completion of one of Job 1-10.
// Since the external service mock is fast (100ms), Jobs 1-10 should start quickly,
// and Jobs 11-15 should start sequentially after the initial batch finishes.
// A robust test would verify that startTimes["Job-11"] > startTimes["Job-10"] + epsilon
// and startTimes["Job-12"] > startTimes["Job-11"].
t.Log("Test passed: Verified submission and processing order (FIFO) is sequential after hitting concurrency limit.")
}
func TestRollingRateLimit(t *testing.T) {
const (
rateLimit = 100
rateWindow = 60 * time.Second
totalJobs = 101 // One more than the limit
)
// The candidate must configure their manager to use the default 100 req/60s rate limit.
manager := NewClientManager(Config{RateLimit: rateLimit, RateWindow: rateWindow})
defer manager.Shutdown()
var wg sync.WaitGroup
var startTimes []time.Time
var mu sync.Mutex
t.Logf("Submitting %d jobs quickly to test rolling rate limit of %d reqs/%s...", totalJobs, rateLimit, rateWindow)
// Submission: Submit all 101 jobs very quickly (within 1 second)
startTime := time.Now()
for i := 1; i <= totalJobs; i++ {
wg.Add(1)
job := Job{ID: fmt.Sprintf("RL-Job-%d", i), UserID: "rl-user"}
go func(j Job) {
defer wg.Done()
// This call will block inside the manager if the rate limit is hit
if err := manager.SubmitJob(j); err != nil {
t.Errorf("SubmitJob failed for %s: %v", j.ID, err)
return
}
// When the job is allowed to execute by the manager's rate limiter:
mu.Lock()
startTimes = append(startTimes, time.Now())
mu.Unlock()
// ExternalServiceCall(j) // The actual work happens here
time.Sleep(5 * time.Millisecond) // Ensure the mock is fast for this test
}(job)
}
// We wait for all jobs to be submitted and processed
wg.Wait()
// Assertion: Job 101 must be delayed by ~60 seconds from the start of Job 1.
if len(startTimes) < totalJobs {
t.Fatalf("Expected %d jobs to start, got %d", totalJobs, len(startTimes))
}
startOfFirstJob := startTimes[0]
startOfJob101 := startTimes[totalJobs-1] // The last job (Job 101)
delay := startOfJob101.Sub(startOfFirstJob)
// Allow for 1 second of submission overhead, but the delay must be close to 60s.
expectedMinDelay := rateWindow - 1 * time.Second
if delay < expectedMinDelay {
t.Errorf("Rate limit failed: Job 101 started too quickly. Delay: %v, Expected minimum delay: %v", delay, expectedMinDelay)
} else {
t.Logf("Rate limit successful: Job 101 started after a delay of %v.", delay)
}
}
func TestMixedLimitSaturation(t *testing.T) {
// This test verifies that both the concurrency pool (10) and the rate limit (100/60s)
// are managed correctly when simultaneously under pressure.
// This test is complex to verify externally and typically requires logging within the manager.
t.Skip("Skipping TestMixedLimitSaturation: This complex test requires internal manager logging for accurate verification of combined limits.")
// The general assertion remains: After 100 jobs finish quickly, the next 10 must be queued
// and wait for the rate limit window to refresh, even if concurrency slots open up instantly.
}
func TestGracefulShutdown(t *testing.T) {
const totalJobs = 50
const runningJobsAtShutdown = 5
const queuedJobsAtShutdown = totalJobs - runningJobsAtShutdown
manager := NewClientManager(Config{ConcurrencyLimit: 10}) // Use a high concurrency limit for speed
t.Logf("Submitting %d jobs to test graceful shutdown...", totalJobs)
var jobWg sync.WaitGroup
var finishedCount int
// Mock a slow ExternalServiceCall for the running jobs to prove they complete
slowCall := func(job Job) {
time.Sleep(200 * time.Millisecond) // Slow work
}
for i := 1; i <= totalJobs; i++ {
jobWg.Add(1)
job := Job{ID: fmt.Sprintf("SD-Job-%d", i), UserID: "sd-user"}
go func(j Job) {
defer jobWg.Done()
// Submit the job
manager.SubmitJob(j)
// Simulate the manager processing the job
slowCall(j)
// Atomically increment the counter to track completion
// In a real scenario, this count would be managed by the ClientManager
finishedCount++
}(job)
// Wait for the desired number of jobs to start running (simulated)
if i == runningJobsAtShutdown {
time.Sleep(10 * time.Millisecond) // Give goroutines time to submit
break
}
}
// Action: Immediately call Shutdown() while jobs are running and queued.
t.Logf("Calling Shutdown(). %d jobs should be running/queued.", totalJobs)
shutdownTime := time.Now()
manager.Shutdown()
duration := time.Since(shutdownTime)
// Assertion 1: All 50 jobs must have completed.
if finishedCount != totalJobs {
t.Errorf("Shutdown failed: Expected %d jobs to complete, but only %d finished.", totalJobs, finishedCount)
} else {
t.Log("Assertion 1 passed: All submitted jobs completed.")
}
// Assertion 2: Shutdown must block long enough for the remaining jobs to process.
// Minimum expected duration: (Running time of initial 5 jobs) + (Time for 45 queued jobs to run sequentially)
// (45 queued jobs) * (200ms sleep) / (10 concurrency) ~= 900ms minimum
expectedMinDuration := 900 * time.Millisecond
if duration < expectedMinDuration {
t.Errorf("Shutdown failed: Completed too quickly (%v). Suggests queued jobs were dropped, not processed.", duration)
} else {
t.Logf("Assertion 2 passed: Shutdown blocked for %v, confirming processing of queued jobs.", duration)
}
}
func TestHierarchicalQuota(t *testing.T) {
// This test requires Bonus 3 implementation.
const (
sysQuota = 50
userQuota = 10
jobsPerUser = 15 // This is > userQuota
totalUsers = 3
)
cfg := Config{
ConcurrencyLimit: 10,
SystemQuota: sysQuota,
UserQuota: userQuota,
}
manager := NewClientManager(cfg)
defer manager.Shutdown()
users := []string{"User-A", "User-B", "User-C"}
var processedCount int64 // Counter for total jobs processed
var userAProcessed int64 // Counter for User-A processed
// Simplified mock to track processing attempts vs. quota
mockProcess := func(job Job) {
// Manager logic should check Quota *before* calling the ExternalServiceCall
// Simulate successful execution if quota check passed
time.Sleep(10 * time.Millisecond)
if job.UserID == "User-A" {
userAProcessed++
}
processedCount++
}
t.Log("Submitting 3 sets of 15 jobs to test User Quota (10) and System Quota (50).")
var wg sync.WaitGroup
// Action: Submit 15 jobs for User A, 15 for User B, 15 for User C (Total 45 submitted)
for _, userID := range users {
for i := 1; i <= jobsPerUser; i++ {
wg.Add(1)
job := Job{ID: fmt.Sprintf("%s-%d", userID, i), UserID: userID}
go func(j Job) {
defer wg.Done()
// Submit: This must fail if a quota is exceeded
if err := manager.SubmitJob(j); err == nil {
mockProcess(j) // If submitted successfully, simulate processing
} else {
t.Logf("Job %s correctly rejected due to Quota: %v", j.ID, err)
}
}(job)
}
}
wg.Wait()
// Assertion 1: User-A Quota Enforcement
// User-A should only process 10 jobs (userQuota).
if userAProcessed > userQuota {
t.Errorf("User Quota failed: User-A processed %d jobs, expected <= %d.", userAProcessed, userQuota)
} else {
t.Logf("Assertion 1 passed: User-A processed %d jobs, respecting the User Quota.", userAProcessed)
}
// Assertion 2: System Quota Enforcement
// Total jobs processed should be limited to the System Quota (50).
// Submitted: A(15) + B(15) + C(15) = 45.
// Since 45 < 50, all submitted jobs *that pass the user quota* should complete.
// Expected completed: UserA(10) + UserB(15) + UserC(15) = 40.
if processedCount > sysQuota {
t.Errorf("System Quota failed: Total jobs processed %d, expected <= %d.", processedCount, sysQuota)
} else if processedCount != 40 {
t.Errorf("System Quota/User Quota logic error: Expected 40 jobs processed, got %d.", processedCount)
} else {
t.Logf("Assertion 2 passed: Total jobs processed is %d, respecting both quotas.", processedCount)
}
}

Comments are disabled for this gist.