Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Saraf

Status

📜📞🔧🔧❌

Back-End Developer

Interview Process

flowchart LR
    sr(Send Resume) --> hr(HR Call) --> si(Screening Interview) --> ti(Technical Interview) --rejected--x hri(HR Interview) -.-> o(Offer)

Apply Way

Jobvision

Interview Date

  • Sent Resume
    1404.07.18

  • HR Call
    1404.07.28

  • Screening Interview
    1404.07.30

  • Technical Interview
    1404.08.05

  • Rejection Email
    1404.08.12

Interview Duration

  • Screening Interview
    30 minutes

  • Technical Interview
    1 hours

Interview Platform

Google Meet

Screening Interview

  • Tell me about yourself.

  • Explain what a race condition is in an order-matching / exchange system (for example, in a matching engine). Give concrete examples of how race conditions can occur and describe strategies you would use to prevent or resolve them.

  • How would you design a system that avoids data loss when using a message broker (for example, RabbitMQ)?

Technical Interview (Live Coding)

  • We want to implement a simple token-bucket algorithm in middleware to rate-limit users?

    My Answer Run
    package main
    
    import (
        "fmt"
        "time"
    )
    
    type User struct {
        accountID      int64
        capacity       int64
        counter        int64
        refillRate     int64
        lastRefillTime time.Time
    }
    
    func handler(user User, userData map[int64]User) {
        if _, ok := userData[user.accountID]; ok {
            fmt.Println("OK")
            ud := userData[user.accountID]
            if ud.counter >= ud.capacity {
                fmt.Println(ud.counter)
                panic("rate limit reached")
            }
            ud.counter++
            fmt.Println(ud.counter)
            elapsTime := time.Now().Unix() - ud.lastRefillTime.Unix()
            ud.counter += elapsTime * ud.refillRate
        } else {
            u := User{accountID: 123, capacity: 10, counter: 0, refillRate: 1}
            userData[u.accountID] = u
        }
        fmt.Println(user.counter, " ", user.capacity, " ", user.refillRate, " ", user.lastRefillTime)
    }
    
    func main() {
        userData := make(map[int64]User, 0)
        newUser := User{accountID: 123, capacity: 10, counter: 0, refillRate: 1, lastRefillTime: time.Now()}
        for i := range 10 {
            fmt.Println("i:", i)
            handler(newUser, userData)
        }
    }
    

    این‌جا اشتباهم این بود که مقدار map رو عوض کردم دوباره نذاشتم توش.

    Answer Run
    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    type User struct {
        accountID      int64
        capacity       int64
        tokens         int64
        refillRate     int64
        lastRefillTime time.Time
        mutex          sync.Mutex
    }
    
    type TokenBucketManager struct {
        users map[int64]*User
        mutex sync.RWMutex
    }
    
    func NewTokenBucketManager() *TokenBucketManager {
        return &TokenBucketManager{
            users: make(map[int64]*User),
        }
    }
    
    func (tm *TokenBucketManager) GetOrCreateUser(accountID int64, capacity, refillRate int64) *User {
        tm.mutex.Lock()
        defer tm.mutex.Unlock()
    
        if user, exists := tm.users[accountID]; exists {
            return user
        }
    
        user := &User{
            accountID:      accountID,
            capacity:       capacity,
            tokens:         capacity, // Start with full bucket
            refillRate:     refillRate,
            lastRefillTime: time.Now(),
        }
        tm.users[accountID] = user
        return user
    }
    
    func (u *User) refill() {
        now := time.Now()
        elapsed := now.Sub(u.lastRefillTime)
    
        // Calculate tokens to add based on elapsed time
        tokensToAdd := int64(elapsed.Seconds()) * u.refillRate
        if tokensToAdd > 0 {
            u.tokens = min(u.tokens+tokensToAdd, u.capacity)
            u.lastRefillTime = now
        }
    }
    
    func (u *User) AllowRequest() {
        u.mutex.Lock()
        defer u.mutex.Unlock()
    
        // Refill tokens based on time elapsed
        u.refill()
    
        // Check if we have at least one token
        if u.tokens > 0 {
            u.tokens--
            fmt.Printf("Request allowed. Tokens remaining: %d\n", u.tokens)
            return
        }
    
        // If no tokens available, panic
        panic("rate limit reached")
    }
    
    func min(a, b int64) int64 {
        if a < b {
            return a
        }
        return b
    }
    
    // Middleware handler function
    func (tm *TokenBucketManager) RateLimitMiddleware(accountID int64) {
        user := tm.GetOrCreateUser(accountID, 10, 1) // capacity=10, refillRate=1 token/sec
        user.AllowRequest()
    }
    
    func main() {
        tokenManager := NewTokenBucketManager()
    
        // Simulate requests with panic recovery
        for i := 0; i < 15; i++ {
            func() {
                defer func() {
                    if r := recover(); r != nil {
                        fmt.Printf("Request %d: %v\n", i+1, r)
                    }
                }()
    
                fmt.Printf("Request %d: ", i+1)
                tokenManager.RateLimitMiddleware(123)
            }()
    
            // Add some delay to see the refill in action
            if i == 9 { // After 10th request, wait to see refill
                fmt.Println("Waiting 2 seconds for token refill...")
                time.Sleep(2 * time.Second)
            } else {
                time.Sleep(100 * time.Millisecond)
            }
        }
    }
    

Score

6/10

در کل خوب بود. استک php داشتن می‌خواستن سوییچ کنن رو go و تیم فلت بود، تعداد بکندها هم ۶ نفر و این یعنی فشار کاری! یه مقدار شاید اگه مسلط‌تر لایوکد رو می‌زدم اوکی می‌شد اما خب خیلی هم شرکتی نبود که براش ناراحت بشم.