Thread-safe database connection pool with blocking acquire
I was asked this
No reports yet. Sign in to say where you were asked it.
You are given a mocked database whose connections can run query. Write a connection pool that keeps a fixed set of connections open and lends them out: acquire() hands a caller a connection, and release() gives it back so the next caller can reuse it. The pool will be used from several threads at once.
Interface
Unless you agree on a different interface with the interviewer, assume:
-
MockDB.connect() -> Connectionopens a connection (slow);Connection.query(sql: str) -> listruns a query;Connection.close(). -
ConnectionPool(connect: Callable[[], Connection], size: int)manages at mostsizeconnections. -
acquire(timeout: float | None = None) -> Connectionreturns a free connection, opening a new one only while fewer thansizeexist. If all are lent out, it blocks until one is released, or raisesTimeoutErroraftertimeoutseconds. -
release(conn: Connection) -> Nonereturns a connection. Releasing a connection the pool did not lend, or releasing it twice, raisesValueError. -
close() -> Nonecloses every idle connection and makes lateracquirecalls fail.
Example
pool = ConnectionPool(MockDB.connect, size=2)
c1 = pool.acquire() # opens connection #1
c2 = pool.acquire() # opens connection #2
pool.acquire(timeout=0.1) -> TimeoutError # both are lent out
pool.release(c1)
c3 = pool.acquire() # no new connection opened
c3 is c1 -> True
pool.release(c2)
pool.release(c2) -> ValueError # released twice
Constraints
-
sizeis small (tens); many threads may callacquireandreleaseconcurrently. -
connect()can fail or be slow; a query can raise.
Clarifying questions
- Should connections be opened up front or lazily on demand?
- What should
acquiredo when the pool is exhausted: block, time out, or fail at once? - How do we detect a broken connection, and should the pool replace it?
- Should waiting callers be served in arrival order?
What a strong answer covers
- An idle queue plus a count of open connections, guarded by one lock and a condition variable (or a bounded
queue.Queueand a semaphore). - No connection is ever lent to two callers at once, and the total never exceeds
size, including whenconnect()raises (release the slot on failure). - Bookkeeping of lent-out connections so a double or foreign release is caught.
- A context manager (
with pool.connection() as conn:) so a connection goes back even when the query raises. - Tests with many threads: no more than
sizeconnections open, every caller eventually served, timeouts honored.
Follow-ups
- Validate a connection before lending it and replace dead ones.
- Close connections idle longer than a limit, and keep a minimum number warm.
- Make an
asyncioversion. - How would you size the pool for a given database and request rate?
Sign in to see the worked answer
The full answer, chapter by chapter, with what interviewers expect at each level. Free with an account: one full answer per company.
What the labs asked this week
A weekly email of what OpenAI, Anthropic and the other top AI labs asked engineers, round by round.
Sign in to see the worked answer
The full answer, chapter by chapter, with what interviewers expect at each level. Free with an account: one full answer per company.
Sign in to submit your code; every attempt is kept here.
