POST /lock/acquire
{ "resource": "X", "client_id": "C1", "ttl": 5000 }
POST /lock/release
{ "resource": "X", "lease_id": "abc123" }
POST /lock/renew
{ "lease_id": "abc123", "ttl": 5000 }
resource: The unique identifier of the thing you want to lock (e.g., "file_123", "user:42").
client_id: The ID of the client (or session) requesting the lock.
ttl: Time-to-live (in milliseconds). How long the lock should be valid before it auto-expires.
KV stores like etcd, Consul, ZooKeeper, Redis provide:
/locks/
resource_X = {"owner_id":"C1","lease_id":"abc123","expires_at":1700000123}
/queues/
resource_X/
1695055500000_c2 = {"client_id":"C2","requested_ttl":5000}
1695055501000_c3 = {"client_id":"C3","requested_ttl":5000}
/leases/
abc123 = {"resource_key":"resource_X","owner_id":"C1","expires_at":1700000123}
Consensus Metadata Store (Raft cluster like etcd): authoritative lock state & durable FIFO queues, fencing token generation, wait-for graph for detection. Guarantees linearizability.
API Gateway (stateless): accept client requests, forward to metadata store (or local cache for granted locks), handle renewals, timeouts, and metrics.
Clients : robust client library with heartbeat/renew, local retry/backoff, and API wrappers.
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Explain any trade offs you have made and why you made certain tech choices...
Try to discuss as many failure scenarios/bottlenecks as possible.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?