Confluent builds a data streaming platform powered by Apache Kafka, including Confluent Cloud. Software Engineers design, build and scale distributed systems, cloud-native services and low-latency infrastructure. The problem areas include distributed consensus, stateful stream processing, high-throughput storage engines, multi-tenant cloud architecture and resource scheduling. Examples of the day-to-day work include optimising storage engines such as RocksDB, building high-availability cloud APIs and writing concurrency abstractions in Java.
Other day-to-day work in the role: services and control planes that manage Kafka clusters, tuning storage, memory and execution paths in Confluent Cloud, code review, unit, integration and chaos testing, design reviews and written design documents, and on-call shifts with post-mortems. Engineers work with Product Management, SRE, Cloud Operations and Security.
The interview questions candidates report follow the same pattern. The coding questions are practical rather than puzzle-like: emulate tail -n on arbitrary file sizes, build a function registry that handles overloading and variadic arguments, solve Sudoku with backtracking. The concurrency questions ask you to build thread-safe structures yourself, such as an LRU cache or a time-windowed map. The design questions reach down to storage-engine internals (write-ahead logs, memtables, SSTables, Bloom filters, compaction) and to how partitioning and replication behave when a node fails. Prepare for depth under those abstractions rather than for naming the right library.
Initial HR Alignment
reportedCandidates describe this stage as initial outreach to align on qualifications and role expectations. Its practical value to you is information. Confluent engineers work in Java, Go, C++ or Python depending on the team, and candidates report multi-threading sessions and being asked to run their code in later rounds. So use this stage to learn which language and environment the technical screen uses, and which team domain the role sits in. Give a short summary of your systems background that names the languages you have written concurrent code in and the distributed or storage systems you have owned.
What to demonstrate
- Whether your background matches the role's expectations, which is the stated purpose of this stage
- Whether you can summarise your systems experience (languages, concurrency, distributed services) clearly and without drifting into a full project walkthrough
How to prepare
- Prepare a short spoken summary naming your main language, one concurrent component you built and one distributed or storage system you worked on, with a single concrete figure for each
- Ask which language and coding environment the technical screen uses, and whether you will execute code and write tests there
- Ask which team or product area the role sits in, so you know whether to weight storage internals, cloud services or client-facing APIs in your design practice
Technical Screen
reportedCandidates describe the technical screen as a preliminary check of coding skills and technical knowledge. Plan to run your code at this stage, cover edge cases and write working unit tests. The reported coding questions, which candidates describe across screening and loop interviews, are practical: a tail -n utility for arbitrary file sizes, a function registry that handles overloading and variadic arguments, Sudoku validation and solving, ranking songs by pairwise preferences, and a constrained traversal over a weighted graph. Treat any problem you get as a small piece of production code. Clarify input size and memory bounds, write it so it compiles and runs, then prove it with the tests you chose.
What to demonstrate
- Coding skills and technical knowledge, the two things candidates name for this stage
- Whether your code runs, with correct syntax, handled edge cases and tests you can point to
- Whether you pick a data structure that fits the stated constraint rather than the first one that comes to mind
How to prepare
- Implement
tail -nfor a file larger than memory: seek to the end, read fixed-size blocks backwards, count newlines, and test an empty file, n = 0, n larger than the line count, and a file with no trailing newline - Build a function registry with a trie or nested map keyed by argument types, where a variadic signature matches a call with any number of trailing arguments of its type. Test exact-match precedence over a variadic match
- Practise in an editor where you compile and run code, writing two or three unit tests before you say you are done
Virtual Onsite Loop
reportedCandidates describe the virtual onsite as a set of sessions covering coding, multi-threading, system design and a technical deep dive, and report at least one session dedicated to concurrent data structures and synchronization. In that session, don't reach for high-level concurrent collections like ConcurrentHashMap unless the interviewer invites you to; be ready to build the synchronization with explicit locks or primitives. Topics to prepare for the design session include storage-engine mechanics, partitioning and replication, API and schema design, and back-of-the-envelope numbers. Candidates describe the deep dive as a walk through a past project: architecture, failure modes and why one option was chosen over another.
What to demonstrate
- Multi-threading built on explicit primitives: locks, read-write locks, atomics, semaphores and condition waits, with races, deadlocks and starvation reasoned about out loud
- System design that goes below the boxes: write and read paths through a WAL, memtable and SSTables, partitioning with consistent hashing, and what replication and rebalancing do when a node fails
- Clean API specifications, schema choices and estimates with stated assumptions
- In the deep dive, whether you can explain the trade-offs, hidden edge cases and degradation behaviour of a system you actually built
How to prepare
- Write a bounded blocking queue using one lock and two conditions, then an LRU cache, and explain why an LRU
getis a write (it moves a node) so a read lock alone does not protect it - Design a single-node key-value store from write-ahead log to compaction, and say what a Bloom filter saves on a read that misses
- Explain on paper which keys move under consistent hashing when a node leaves, and how a follower is promoted and caught up
- Prepare one project to deep-dive depth: a diagram, the alternatives you rejected, one failure you saw in production, and the figures you will quote
Managerial Rounds
reportedCandidates describe the managerial rounds as interviews on managerial fit and cultural alignment within the team. The reported behavioral questions (not tied to a specific round) cover architectural trade-offs under deadline or customer pressure, difficult technical feedback, debugging a severe outage when metrics and logs disagree, pushing for a technical direction against senior pushback, and an outage you caused or contributed to. Pick stories with engineering content: the trade-off you made, what you measured and what changed. Keep the figures consistent with anything you said about the same project in the deep dive.
What to demonstrate
- How you make and explain trade-offs under deadline or customer constraints
- How you handle feedback, disagreement with senior peers, and your own mistakes, including the preventive change that followed
- How you reason through a production incident when the signals conflict
How to prepare
- Write one story per reported behavioral prompt, each with the decision, the evidence behind it, the result and what you would change
- For the outage story, name the root cause, the detection gap and the concrete preventive measure, and state your own part in it plainly
- Check each story against your deep-dive project sheet so team size, scale and timeline match
10 candidate reports. Individual accounts describe a particular role and hiring cycle.
Confluent Account Executive interview with a defense-sector role mismatch
My experience started with a recruiter who seemed supportive, but the initial description of the role, especially its stated focus on the defense sector, didn't match what I later heard from the interviewers. That mismatch made me wary of how clearly the role had been defined. Once I entered the interviews, it was hard to pin down the day-to-day responsibilities and scope. Both conversations star…
Read full experienceConfluent Software Engineer interview with system design and DSA rounds
My process had three segments. First, I completed a qualifying technical round. Then came the heavier middle section: three rounds combining system design with DSA, with the DSA portion mostly resembling LeetCode medium difficulty. The final segment was a behavioral round with a senior manager. The process felt difficult because the middle block required sustained technical thinking across severa…
Read full experienceConfluent Solutions Engineer interview: cloud and data management focus
My biggest issue started before the technical work. The role requirements felt misrepresented. I spent time with the recruiter and hiring manager discussing my background in detail, and they explicitly told me that specialized knowledge of their products or data streaming wasn't required. When the one-hour technical interview came, the focus didn't match what I had been led to expect. The convers…
Read full experienceConfluent Software Engineer interview with two technical rounds and harder follow-ups
My interview had a small set of core stages: recruiter coordination, two technical interviews, and a manager round. The problems were medium overall, with some harder follow-ups that required me to stay sharp after I thought I’d settled into the first question. I had a generally positive impression of the process. The recruiters were responsive and supportive, and it took only a few weeks from my…
Read full experienceConfluent Software Engineer interview with a four-round virtual onsite
A recruiter reached out to me on LinkedIn, and the process started with a coding conversation with a senior engineer. That round went really well. I finished confidently, and the interviewer seemed genuinely impressed. What followed felt chaotic and stressful. I was moved into a virtual onsite almost immediately. It covered four rounds over two days, including coding, a hiring manager discussion,…
Read full experiencePracHub editorial advice for the preparation topics above.
Answering the multi-threading session with ConcurrentHashMap or a library queue when the question was to build the synchronization
Don't rely only on high-level concurrent collections in a multi-threading session unless the interviewer invites it. Ask early whether library concurrent types are allowed. If they aren't, build the structure with a ReentrantLock and its Conditions (or a ReadWriteLock where concurrent readers actually help; its read lock cannot create a Condition, so waiting logic belongs on a plain ReentrantLock), and say which invariant each lock protects. Knowing why a bounded queue usually uses two conditions (notFull and notEmpty) so a signal wakes the right side, and why await sits in a while loop (spurious wakeups, and another thread taking the slot first), is worth more than knowing the name of the library class.
Building a thread-safe cache or time-windowed map from two individually safe pieces that together are not atomic
An LRU cache is a map plus a linked list, and a time-windowed map is a map plus an expiry order. If each piece has its own lock, or the expiry check and the read happen in separate critical sections, another thread can see a key that is in the map but not in the list, or read a value that expired between the check and the return. Put one lock around each compound operation, or justify a finer scheme out loud. Also note that an LRU get changes recency, so a read-write lock gives no concurrency benefit unless you change the eviction design.
Declaring a technical-screen solution finished without running it or testing its edge cases
Plan to run your code in the technical screen, check its syntax, cover edge cases and write working unit tests, and leave time for all of it. For tail -n, test an empty file, n = 0, n larger than the file's line count, a file without a trailing newline, and a line that crosses a read-block boundary. When a test fails, name the input, the expected output and the actual output before you change anything.
Answering the key-value store or cluster-failure design question with block diagrams and no write or read path
The reported design questions go down to WAL, memtables, SSTables, Bloom filters and compaction, and to how consistent hashing, leader-follower replication and rebalancing behave when a node fails. Walk one write from append to fsync, to memtable, to flush. Walk one read through the memtable, the Bloom filters and the SSTable levels. Say what recovery replays after a crash, and name the cost of compaction: write amplification and I/O competing with foreground traffic. For the cluster question, say which partitions lose their leader, who takes over, and what happens to writes that were acknowledged but not yet replicated.
Losing a trade-off argument in the technical deep dive because the project figures or the reason for a choice shift under questioning
Before the onsite, write one page per project you might discuss: scale, team size, timeline, the alternatives you rejected and why, and one failure you saw in production. Quote from that page in the deep dive and in the managerial rounds, so the same project sounds the same both times. If you don't know a figure, say so rather than estimating it in the moment.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Design and write a function registration module supporting method over…
Design and write a function registration module supporting method overloading and variadic arguments using a Trie or nested HashMap data structure.
Approach
- State the target complexity and say which constraint rules the naive version out.
- Walk one small example through your approach before writing the whole thing.
- Name the brute-force solution and its complexity before improving on it.
Follow-up
- Which test case would catch an off-by-one here?
- What is the worst case, and how likely is it on real data?
Implement a custom file-reading utility that emulates the behavior of …
Implement a custom file-reading utility that emulates the behavior of the Unix tail -n command efficiently for arbitrary file sizes.
Approach
- Restate the input: its shape, its size, and what is guaranteed about it.
- State the target complexity and say which constraint rules the naive version out.
- Choose the data structure from the access pattern, not from familiarity.
Follow-up
- How does this change if the input no longer fits in memory?
- What is the worst case, and how likely is it on real data?
Implement a time-windowed HashMap that automatically expires or evicts…
Implement a time-windowed HashMap that automatically expires or evicts keys outside a configured sliding time window in a thread-safe manner.
Approach
- Distinguish a value from a reference to it, and say which one you handed out.
- Reach for the cheapest primitive that closes the race, not the broadest lock.
- Say what the runtime actually does before reasoning about the code.
Follow-up
- Where could this allocate more than you expect?
- What happens if two callers reach this at the same time?
Explain and demonstrate the practical differences between Java's `sync…
Explain and demonstrate the practical differences between Java's synchronized keyword, ReentrantLock, and ReadWriteLock in high-throughput read-heavy systems.
Approach
- Reach for the cheapest primitive that closes the race, not the broadest lock.
- Say what the runtime actually does before reasoning about the code.
- Name what is shared across threads and what owns each piece of state.
Follow-up
- How would you prove the race exists rather than suspect it?
- Where could this allocate more than you expect?
Seal an hour under late data with bounded memory
Metering ingest reads 256 partitions at 10,000 to 40,000 events/second. Events carry occurred_at and ingested_at, and during a producer replay the gap between them is hours. Seal each UTC hour once no more than 50 parts per million of that hour's eventual quantity can still arrive, using memory that does not grow with the size of the replay. Define the watermark, the lateness parameter and how you measure it, the structure holding open hours, and the write that performs the seal. State what an idle partition does to your watermark.
Approach
- Two clocks, two jobs. Bucket by
occurred_at, because that is the hour the customer is billed for, and advance the watermark oningested_at, because that is what the fold has consumed and whatsource_max_ingested_atrecords. Conflating them is what makes late data invisible. - The global watermark is the min over partitions of each partition's committed
ingested_at, not the max: the fold is trustworthy only as far as the slowest partition. The consequence is that one idle partition pins the watermark forever and nothing seals, so an idle partition must promote its watermark to wall clock after a stated idle timeout, and that timeout becomes a correctness parameter, because a partition that is slow rather than idle gets sealed past. - Choose the lateness L from the measured distribution of
ingested_at - occurred_at, weighted by quantity rather than by event count. The target is 50 ppm of the hour's quantity, and a replay is rare in events while carrying disproportionate mass, so an event-weighted quantile picks an L that is comfortably wrong at exactly the moment it matters. - Measure that quantile in bounded memory. A Greenwald-Khanna summary gives epsilon-approximate quantiles in O((1/epsilon) log(epsilon n)) space; a t-digest costs more per merge but has relative error that tightens at the tails, which is the half of the distribution you are reading at p99.99. Keep a separate summary per tenant class, because one tenant's batch importer is not the population.
- Hold open hours in a min-heap keyed by
hour_start. When the watermark advances, pop every hour withhour_end + L < Wand seal it: O(log H_open) per advance and O(1) amortised per event to touch its bucket. Memory is open hours multiplied by distinct(tenant, workspace, sku)keys, so cap the number of simultaneously open hours and spill the oldest intousage_rollup_hourlyasstatus='open'with arevisionbump. While an hour is open the row is upsertable, so the store is your overflow. - The seal itself is a conditional write:
update ... set status='sealed', sealed_at=now() where status='open' returning .... Two sealers race on every restart, and the loser must see zero rows and stop rather than write a second value. After the seal, an event for that hour is not an upsert but an adjustment, andsource_max_ingested_atis what proves it arrived afterwards.
Worked solution 40 min
- Replay a day of events with a synthetic lateness distribution: 99.9% under two minutes, plus a 0.05% tail at four to six hours that carries 3% of total quantity.
- Compute the p99.99 lateness two ways, event-weighted and quantity-weighted, and put the two numbers side by side.
- Implement the min-heap of open hours with the watermark as the min over 256 partitions, then stall one partition for 20 minutes and observe what seals.
- Set the idle-partition timeout to 60 seconds, repeat the stall, and measure how much quantity arrives after the seal.
- Attempt the seal from two workers at once and confirm the conditional update lets exactly one through.
Follow-up
- A replay starts during the sealing window for a period you are about to close. What do you do, and what is the customer-visible consequence of each option?
- Your measured quantity-weighted p99.99 lateness is six hours and the invoice must be issued at 02:00 UTC on the first. How do you reconcile those two numbers?
- How would you detect that L has drifted before it costs you an hour's quantity?
Enforce a concurrent-run quota that survives simultaneous requests
A plan allows at most 20 concurrently running rows in job_run per tenant. The table holds run_id, tenant_id, workspace_id, status (queued, leased, running, succeeded, failed, timed_out, cancelled, lost), lease_token, leased_until, started_at and finished_at. Today the service runs select count(*) from job_run where tenant_id = $1 and status = 'running', compares the result to 20, then inserts. Under load a tenant exceeds the cap by exactly the number of concurrent requests. Name the anomaly, say which isolation levels do and do not prevent it, and give a version that holds, as SQL.
Approach
- Name it: write skew. Each transaction reads a predicate (the count of running rows), neither modifies what the other read, and both then insert rows that jointly violate an invariant no single row expresses. Read committed permits it. So does repeatable read, because snapshot isolation's first-updater-wins check fires only on conflicting row updates, and these are inserts touching disjoint rows.
- Enumerate the fixes with their real costs. SERIALIZABLE works: PostgreSQL's SSI tracks the predicate read and aborts one transaction with SQLSTATE 40001, which obliges the caller to retry and makes the abort rate rise with contention on a hot tenant. Folding the predicate into the write as
insert ... select ... where (select count(*) ...) < 20narrows the race to the statement's snapshot but does not close it under read committed. - Give the version that holds at read committed: serialise on a row both transactions must touch.
update tenant_concurrency set running = running + 1 where tenant_id = $1 and running < 20 returning runningupdates zero rows when the cap is reached, and zero rows is the rejection. This works because at read committed a blocked UPDATE re-evaluates its WHERE clause against the newly committed row; at repeatable read the same statement raises a serialisation error instead, so the isolation level changes the calling contract. - State the cost you just bought. That row is now a per-tenant serialisation point, so admission throughput for the tenant is bounded by one divided by the lock hold time; at a 2 ms hold that is roughly 500 admissions/second. Keep the critical section to the single UPDATE, with no network call or scheduling decision inside the transaction, and decrement in the same transaction that writes the terminal status.
- Close the leak the status enum implies: a run can end as
lost, so a crashed worker otherwise consumes a slot forever. Reconcile on a schedule againststatus = 'running' and leased_until < now(), and treat the counter as a fast path overjob_run, which stays the system of record.
Follow-up
- Write the retry loop for the SERIALIZABLE version. What does the caller see when it keeps aborting, and what bounds the retries?
- Two regions each keep a counter. What is the effective cap, and what does admission do when the counter store is unreachable?
- The cap changes mid-flight on a plan upgrade. Do running jobs get killed, and what does the counter row look like during the change?
Rebuild an hourly rollup with deduplication and late-arrival accounting
From usage_event (event_id, tenant_id, workspace_id, environment, sku, quantity numeric(20,6), idempotency_key, occurred_at, ingested_at), produce the values usage_rollup_hourly should hold for one tenant over one day: per (workspace_id, sku, hour_start) the deduplicated quantity_sum, event_count and source_max_ingested_at, bucketed by occurred_at. Duplicates share (tenant_id, idempotency_key). Also report, per hour, the running total across the day and the share of quantity that arrived more than two hours after the hour began. Write the query, and state which duplicates a daily unique index cannot catch.
Approach
- Deduplicate in its own CTE before any aggregation, because a SUM cannot be un-summed:
row_number() over (partition by tenant_id, idempotency_key order by ingested_at, event_id) = 1. Include the tiebreaker. Without it the surviving row is non-deterministic when two duplicates share an ingested_at, and a rollup described as deterministically recomputable then disagrees with itself between runs. - Bucket on occurred_at and nothing else, and pin the timezone explicitly.
date_trunc('hour', timestamptz)truncates in the session's TimeZone setting, so the same query run by a session set to a non-UTC zone buckets differently; use the three-argumentdate_trunc('hour', occurred_at, 'UTC')on PostgreSQL 16 or later, ordate_trunc('hour', occurred_at at time zone 'UTC') at time zone 'UTC'before that. Filterenvironment = 'production'explicitly, since metering covers three environments and billing covers one. - Aggregate to the grain with
sum(quantity),count(*)andmax(ingested_at). The last is not decoration: it is the watermark the row consumed up to, and without it there is no way to prove afterwards what a number did and did not include. - Compute the late share inside the dedup-and-aggregate step as a conditional aggregate,
sum(quantity) filter (where ingested_at > hour_start + interval '2 hours'), then divide by the hour's total. Compute the running total as a window over the already aggregated rows:sum(quantity_sum) over (partition by workspace_id, sku order by hour_start rows between unbounded preceding and current row). Running either over raw rows puts the duplicates back. - Answer the index question exactly. The unique constraint is on (ingested_day, tenant_id, idempotency_key), because a unique index on a partitioned table must contain the partition key. It therefore deduplicates only within one ingest day and admits a duplicate whose retry crosses midnight or whose replay runs a week later. That is why this CTE dedups across the whole window being recomputed, and why the dedup horizon is a correctness parameter rather than a retention cost.
- Keep the numeric type all the way through. quantity is numeric so the sums are exact; a cast to double precision anywhere in this pipeline reintroduces drift that surfaces only as a few unreconcilable cents per tenant per month, long after the query is out of anyone's mind.
Worked solution 40 min
- Generate a day of events for one tenant across three workspaces and two SKUs, inject 2% duplicates sharing an idempotency_key with a later ingested_at, and inject 1% whose ingested_at is six hours past occurred_at.
- Write the dedup CTE alone and confirm its row count drops by exactly the injected duplicate count.
- Aggregate and compare quantity_sum against a ground truth computed outside SQL from the generator's own records.
- Add the two window and filtered aggregates, and confirm the final hour's running total equals the ungrouped day total for each (workspace, sku).
- Run the whole query twice over static data and diff the two outputs.
- Re-run with the session TimeZone set to a non-UTC zone and confirm hour_start does not move.
Follow-up
- A dispute forces the same recompute over 40 days for one tenant. What changes about the dedup CTE's memory use and the chosen plan, and what would you do about it?
- Two runs a minute apart return different quantity_sum values for an hour that is already closed. Give two mechanisms that produce that, and the single query that distinguishes them.
- Express the same rollup incrementally so it does not re-scan the day each time the watermark advances. What does the incremental version stop being able to answer?
Explain how consistent hashing, leader-follower replication, and parti…
Explain how consistent hashing, leader-follower replication, and partition rebalancing operate during node failure scenarios in a stateful cluster.
Approach
- Choose a partition key and say what query it makes expensive.
- Name the read and write paths separately; they rarely have the same bottleneck.
- State the consistency you need, and where you are willing to be stale.
Follow-up
- How does this behave when that dependency is down for an hour?
- What breaks first when traffic grows ten times?
Design a real-time message delivery system that tracks message deliver…
Design a real-time message delivery system that tracks message delivery statuses across distributed consumers while enforcing strict rate limits per client.
Approach
- Name the failure you are designing for, then the recovery path.
- Name the read and write paths separately; they rarely have the same bottleneck.
- Choose a partition key and say what query it makes expensive.
Follow-up
- How does this behave when that dependency is down for an hour?
- What breaks first when traffic grows ten times?
Architect a scalable short URL service (TinyURL) capable of handling h…
Architect a scalable short URL service (TinyURL) capable of handling high write concurrency, outlining base encoding schemes, primary key generation, and cache strategies.
Approach
- State the consistency you need, and where you are willing to be stale.
- Name the failure you are designing for, then the recovery path.
- Choose a partition key and say what query it makes expensive.
Follow-up
- What breaks first when traffic grows ten times?
- What would you drop to keep the system up under load?
Publish limit semantics that clients can back off against
The gateway enforces three separate limits: a per-tenant token bucket, a monthly plan quota, and a cap on concurrent in-flight requests. Tenants hold several credentials and call from three regions, and today they see undifferentiated 429s. Design the client-facing contract: which headers carry which limit, the status codes that distinguish slow down from out of plan allowance from too many in flight, and what a well-behaved SDK does for each. Also state what the gateway returns when the shared counter store is unreachable, and what bound that choice implies.
Approach
- Separate the three objects before naming a header. A bucket refills continuously, a quota does not refill until the period rolls, and a concurrency cap clears when an in-flight request finishes. They have different remedies, so they cannot share a status code.
- Map them accordingly: 429 with Retry-After for the bucket, where waiting works; 429 with a distinct code and a reset hint for concurrency, where waiting works only if something else completes; and 402 or 403 with a plan code for quota, where waiting never works and the SDK must surface it rather than sleep on it.
- Emit RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset for the bucket only, and document Remaining as advisory. It comes from a shared counter that other requests are changing concurrently, so a client treating it as a reservation has built a race.
- State the aggregation in the docs: the limit applies per tenant across every credential and every region. The cheap per-pod bucket of rate/N is correct only when traffic spreads evenly, and a tenant whose connections land on a few pods is throttled well under its published limit while a widely spread one exceeds it.
- Decide the degraded mode in advance and publish it. Failing open serves unmetered traffic during a counter outage; failing closed converts a counter outage into a total outage. Pick one, bound it, for example a local fallback bucket at a fraction of the limit for the duration, and say so in the contract.
- Specify SDK behaviour: honour Retry-After over local backoff, apply full jitter otherwise, never retry 402 or 403, and cap total attempts so retries expire before the caller's own deadline.
Worked solution 25 min
- Write a three-row table of limit, refill behaviour, status code, headers, and the client's correct action.
- Write the exact header set for one throttled response and one quota-exhausted response, showing that they differ.
- Write the documentation sentence that states aggregation across credentials and regions, and the sentence marking Remaining advisory.
- Choose and justify the counter-store failure behaviour, then state the numeric bound it puts on overage or on availability.
- Write the SDK's decision function: given status and headers, return sleep duration or surface to the caller.
Follow-up
- Two services under the same tenant each read Remaining = 50 and each send 50 requests. What did the contract promise, and what actually happens?
- How would you keep a burst from a staging workspace out of the production workspace's share of the same tenant's bucket?
One tenant's counter writes stall the whole connection pool
A change that made a per-tenant usage counter correct now produces site-wide latency whenever one large tenant writes: unrelated endpoints time out waiting for a connection while database CPU stays low and no statement is slow. The change wraps the counter update in a transaction that takes SELECT ... FOR UPDATE on one row, calls an external pricing service, then updates and commits. Give an ordered checklist, the arithmetic that bounds that tenant's write rate, and three repairs with the cost each one accepts.
Approach
- Separate waiting from working. Low database CPU alongside high application latency points at a queue, so instrument connection-acquisition wait separately from query execution time; that queue forms in the application and is invisible in database metrics, which is why the database looks healthy throughout.
- Confirm the lock rather than assuming it: sample waiting sessions and group by wait event, relation and tuple. Contention concentrated on one tuple belonging to one tenant is the signature; a deadlock would instead show the database aborting transactions after its detection timeout, which is not happening here.
- Do the arithmetic out loud. Throughput on a serialised row is one divided by the lock hold time, and the hold spans the external call, so a 20 ms pricing call caps that tenant near 50 writes per second no matter how many pods run. Every waiter also holds a pooled connection while it queues, so the shared pool drains and unrelated tenants fail at acquisition.
- Repair one: shrink the critical section to a single statement with the price resolved before the transaction opens. Cost is a stale price for the duration of one request and a second round trip; benefit is a hold time measured in the database's own execution time.
- Repairs two and three change where the contention lives rather than how long it is held. Sharding the counter into per-(tenant, bucket) rows and summing on read multiplies write throughput by the shard count, at the cost of an aggregate on every read and a shard count you must size against the largest tenant rather than the median. Accumulating in memory and flushing periodically removes the per-write round trip entirely, paid for with a bounded loss window on crash, which is acceptable for a rate limiter and not for a billing counter.
- Contain independently of which repair wins: a separate pool or per-tenant concurrency cap for this write class, a statement timeout low enough that a pathological query dies before it accumulates waiters, and an idle-in-transaction timeout so a stuck client cannot pin a connection and its locks.
Follow-up
- What would a genuine deadlock look like here, which two code paths would produce one, and how does the database's response differ from what you observed?
- If a transaction-pooling proxy sits in front of the database, which of your three repairs changes behaviour, and what stops working that would have worked on a direct connection?
- The counter also enforces a quota. Why is SELECT the count and then INSERT still wrong after you have fixed the contention?
For a candidate senior enough that the loop turns on design and judgement rather than on whether the coding round gets finished. Five days build one system properly and then stress it; coding gets a single maintenance day, on the assumption that the risk at this level is an unexamined tradeoff rather than a missed algorithm.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Practical coding you actually run
- Implement `tail -n` for a file too large for memory: seek to the end, read fixed-size blocks backwards, count newlines, and stop once n lines are found. Run it against an empty file, n = 0, n greater than the line count, and a file without a trailing newline
- Build the reported function registry with a trie or nested map keyed by argument types. Support overloading and a variadic final parameter, and make an exact signature win over a variadic match
- Write two or three unit tests for each problem before you call it done, in the language you will use in the technical screen
Deliverable: Two working, tested implementations (tail -n and the function registry), each with an edge-case test list.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Backtracking, graphs and ranking
- Validate a Sudoku grid with row, column and box sets, then extend it to a backtracking solver, and state why pruning by candidate sets matters
- Solve a constrained traversal over a weighted graph: choose BFS, DFS or Dijkstra based on whether edge weights differ, and state the complexity
- Rank songs from pairwise user preferences: count head-to-head wins, define the tie-break rule, and say what you do when the preferences contain a cycle
- Practise two more backtracking problems, wildcard pattern matching and a combination sum over reusable values, explaining the backtracking state and the pruning rule out loud
Deliverable: Four solved problems, each with its complexity written down and one test that targets its hardest case.
Practice prompt ↗Practice prompt ↗03Locks and synchronization primitives
- Write a short demo of `synchronized`, `ReentrantLock` and `ReadWriteLock` guarding the same read-heavy map, and explain what each adds: timed and interruptible acquisition, fairness, and concurrent readers
- Build a bounded blocking queue with one lock and two conditions, with `await` inside a `while` loop, and explain why
- Build an LRU cache as a hash map plus doubly linked list under one lock, and explain why an LRU `get` is a write
- List the deadlock, livelock and starvation risks in each structure and how your lock ordering avoids them
Deliverable: Three thread-safe structures you wrote without concurrent collections, each with a one-line invariant per lock.
Practice prompt ↗Practice prompt ↗04Time windows, deduplication and rate limits
- Implement the reported time-windowed map: a map from key to (value, timestamp) plus an expiry queue in time order, with expiry and reads under the same lock
- Build the deduplicator that drops payloads seen within k seconds, and the queue with add, poll and getRandom in O(1) (a map from sequence number to value, with head and tail counters)
- Sketch a sliding-window rate limiter that does not lock the whole store, for example with a lock per client
- Work through the worked coding exercise on sealing an hour under late data, then write a SQL query that finds which keys were active during a requested time range from their start and end events, for the time-window reasoning
Deliverable: Three time-window structures with their eviction logic tested against boundary timestamps.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Storage engines and cluster failure
- Design the reported single-node key-value store: WAL append and fsync, memtable, flush to SSTables, Bloom filters per SSTable, and a compaction strategy with its write-amplification cost
- Explain how consistent hashing, leader-follower replication and partition rebalancing behave when a node fails: which partitions lose their leader, how a new leader is chosen, and what happens to acknowledged writes
- Work through the PracHub bank question Design a distributed key-value store at scale, then compare SQL and NoSQL stores on schema, consistency, scaling and query flexibility, and say what each storage choice makes expensive
Deliverable: One storage-engine design with write path, read path and crash recovery written out, plus a node-failure walkthrough.
Practice prompt ↗Practice prompt ↗06Service design: feeds, short URLs, delivery
- Design the RSS news feed service with a schema, API contracts, a caching layer and a fan-out-on-read vs fan-out-on-write decision justified by the read-to-write ratio
- Design the short URL service: base encoding, how IDs are generated without collisions under concurrent writes, and cache strategy
- Design the message delivery system that tracks delivery status across consumers and enforces per-client rate limits, then compare your limit contract with the worked design exercise on publishing limit semantics
- Put back-of-the-envelope numbers on each design, with every assumption stated
Deliverable: Three designs, each with an API, a data model, one quantified estimate and one named failure mode.
Practice prompt ↗Practice prompt ↗07Technical deep dive and managerial rounds
- Write a one-page sheet for the project you will deep-dive: diagram, scale, team size, rejected alternatives, one production failure and how the system behaved as it degraded
- Write stories for the five reported behavioral prompts: a trade-off under deadline, difficult feedback, an outage with conflicting signals, pushing back on senior peers, and a failure you caused
- Run a mock where someone questions the deep-dive project and then asks a behavioral question about the same project, and compare the two answers for figures that changed
Deliverable: A deep-dive project sheet and five behavioral stories whose facts match each other.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Candidates describe the managerial rounds as covering managerial fit and cultural alignment, and the technical deep dive as a walk through past projects and their trade-offs. The reported behavioral prompts below are not tied to a specific round, and they ask for engineering substance: a trade-off, an outage, a disagreement. For each one, name the decision, the evidence you used, what happened and what you would change, and keep the project facts the same as in your deep dive.
Tell me about a time you received difficult technical feedback from a …
Tell me about a time you received difficult technical feedback from a colleague or manager. How did you process it and adjust your approach?
Approach
- Name the disagreement and how you resolved it with evidence.
- Give the blast radius: what could have broken, and what you measured.
- Close with what you would do differently, concretely.
Follow-up
- What did you decide not to do, and why?
- What would you do differently if you ran that again?
Reverse a webhook ordering decision after measuring its cost
You argued for strict per-subscription ordering in webhook-delivery, which means one in-flight attempt per subscription. It shipped. Three months later a single unresponsive endpoint holds one subscription's queue at a six-hour backlog, and two customers report events arriving out of order anyway once their own retries are counted. Describe a decision you reversed: what you originally optimised for, the measurement that changed your mind, what the reversal cost in engineering time and customer change, and how you told the people who had already built on the original guarantee.
Approach
- State the original decision as a trade you made knowingly. Ordering across a network requires a single in-flight attempt per subscription, and its price is head-of-line blocking whenever one endpoint is slow. 'We priced it wrong' is a much stronger opening than 'we did not realise', and it is usually the true one.
- Bring the measurement that flipped it, not the anecdote: backlog age at the ninety-ninth percentile per subscription, the share of subscriptions where one slow endpoint gated an otherwise healthy queue, and the delivery throughput lost to serialisation. A reversal justified by complaints is indistinguishable from a reversal justified by fatigue.
- Name what you learned about the guarantee itself, which is the engineering content of this story. At-least-once delivery means a retried event already arrives after newer ones and the consumer already must be idempotent, so a guarantee the customer has to defend against anyway was never worth what it cost to provide.
- Describe the migration, because reversing a published contract is the hard half and the part candidates skip. Parallel attempts behind a per-subscription flag, a monotonically increasing sequence number added to the envelope so order-sensitive consumers can sort or discard, documentation that states at-least-once and unordered in those words, and a deprecation measured in quarters because the client is a pinned SDK inside a build pipeline you cannot see or redeploy.
- Give the cost in the two currencies that matter: engineer-weeks, and how many customers had to change code. Then say who you told before it shipped rather than in a changelog afterwards, and which large customer you left on the old behaviour and for how long.
- Close with the signal you now weight differently, stated as something you would do earlier next time: measuring the blocking cost on the slowest decile of endpoints before committing to the guarantee, rather than after a customer noticed.
Follow-up
- A customer insists they need ordering. What do you offer them that is not global serialisation?
- How did you choose the deprecation window given that you cannot see or redeploy the clients?
- What would have to be true for you to reverse back?
Disclose a cross-tenant webhook delivery to affected customers
An enqueue path took the subscription from one lookup and the payload from another. For nineteen minutes, webhook_delivery rows were created whose tenant_id did not match the subscription's tenant, and eleven payloads were signed and sent to four endpoints belonging to other customers. You hold payload_digest, delivery timestamps and response codes. Describe how you handle a disclosure of this kind: what the records prove, what they cannot prove, what you say before you know everything, the one code change that closes it, and which parts you personally drove.
Approach
- Bound the population before saying anything externally. The affected set is deliveries in the window where the event's tenant and the subscription's tenant differ; the ones that actually left are those with delivered_at set and a 2xx in last_response_code. Attempted and delivered are two different counts and a disclosure has to use the right one in the right sentence.
- Separate what the records prove from what they do not, and say both halves rather than the flattering one. They prove which payloads were signed, where they went, and — through payload_digest — exactly which bytes. They do not prove what the receiving system did with them, and they do not bound the window more precisely than your deploy timestamps do.
- Communicate on the facts you hold, with the scope stated as an upper bound: 'at most eleven payloads, four recipient endpoints, these fields, this window' is more useful and more honest than waiting a day for certainty. The field list matters more than the event count, because a customer cannot assess exposure from 'an event'.
- Name the code change precisely, because this class never originates in the delivery worker. Compare the event's tenant against the subscription's tenant at enqueue and again immediately before the payload is signed, and make the second comparison drop the delivery rather than log a warning. Say why one check is insufficient: the enqueue check protects against the bug you know about, the pre-signing check protects the boundary itself.
- Run the history question in parallel and say so: a query over historical deliveries for the same mismatch tells you whether this was nineteen minutes or a year, and you would rather find the second case yourself than have a customer find it after your disclosure.
- Split the response into workstreams with owners — recipients asked to delete, affected customers notified, the check landed with a test, history swept — and say which you personally drove and which you handed off. Claiming all four is not credible and claiming none is not ownership.
Follow-up
- The historical sweep finds two more instances from last year. What changes in what you have already told people?
- Who approves the wording, and what do you do when you are asked to soften the scope?
- A customer asks you to prove a redelivery contained the same bytes as the original. What do you show them?
- 01
Describe a project where you made a significant architectural trade-off due to tight deadlines or customer requirements. What was the outcome?
- 02
Tell me about a time you received difficult technical feedback from a colleague or manager. How did you process it and adjust your approach?
- 03
How do you approach debugging a high-severity production outage when system metrics and logs offer conflicting information?
- 04
Describe a situation where you advocated for a specific technical direction against pushback from senior peers or project stakeholders.
- 05
Walk me through a major software failure or outage you directly caused or contributed to. What root-cause insights did you identify, and what preventive measures did you implement?
Is this an official Confluent interview guide?
No. It is independent research and practice material for the Software Engineer role at Confluent. The rounds and questions reflect what candidates have reported, not a process Confluent has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗What programming languages can I use during the technical interviews?
Candidates report being able to use the language they are most comfortable with, such as Java, C++, Go or Python. For the multi-threading session, choose a language whose locking primitives you can write from memory: Java's ReentrantLock, ReadWriteLock and Condition, Go's sync.Mutex and channels, or C++'s std::mutex and condition_variable. Confirm the coding environment with your recruiter before the technical screen.
PracHub interview research ↗What kind of coding questions come up?
The reported coding questions are practical rather than brainteasers: a `tail -n` utility for arbitrary file sizes, a function registry with overloading and variadic arguments, Sudoku validation and solving, song ranking from pairwise preferences, and a weighted graph traversal. Candidates report medium to hard difficulty. Practise in an editor where you run what you write, handle edge cases and write unit tests.
PracHub interview research ↗Is there a dedicated concurrency round, and can I use ConcurrentHashMap?
Candidates describe multi-threading as one of the virtual onsite sessions and report at least one session dedicated to concurrent data structures. Don't rely only on high-level concurrent collections such as ConcurrentHashMap unless the interviewer invites it. Ask at the start whether library concurrent types are allowed, and be ready to build the structure with explicit locks, conditions or atomics.
PracHub Software Engineer practice ↗Is prior experience with Apache Kafka required?
Candidates report that Kafka experience is a nice-to-have, not a requirement, unless the role is in a specialised domain. The reported questions test data structures, concurrency, storage engines and distributed-systems fundamentals. Knowing how a log-structured store, partitioning and replication work will help you more than knowing Kafka's client APIs.
PracHub interview research ↗How long does the process take?
Candidates report roughly three to five weeks across four stages, and some processes run to six. Timing depends on availability, scheduling and team matching, so ask your recruiter for the expected dates after each stage.
PracHub interview research ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-24 - 02PracHub Software Engineer practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-24 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-24