Sounds straightforward until you actually think about concurrency.
Start by clarifying requirements: pool size, blocking vs. non-blocking acquire, timeout behavior, and thread-safety. Then design a thread-safe pool using a blocking queue of connections, with acquire() taking a connection (blocking or timing out) and release() returning it, ensuring connections are validated and not leaked. Finally, discuss trade-offs like fairness, max pool size, and error handling.
Pro tip: Mention that you would wrap acquire/release in try/finally or context managers to guarantee release even on exceptions, and that you'd add metrics (e.g., wait time, pool utilization) for observability—this shows production maturity.
Ask about expected concurrency, max pool size, whether acquire should block or fail fast, timeout support, and if connections need validation or health checks.
Use a blocking queue (e.g., LinkedBlockingQueue) to hold available connections, which naturally handles blocking acquire and thread-safe release.
acquire() polls or takes from the queue with an optional timeout; if no connection is available, either block, throw an exception, or create a new one up to max size.
release() returns the connection to the queue; ensure it's idempotent and handles invalid connections by discarding and possibly creating a replacement.
Cover fairness (FIFO vs. LIFO), dynamic sizing, connection validation, leak detection, and metrics; mention how you'd test with mocked db.query.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.