User enters a URL and gets a shortened one, redirecting to the exact same URL with a permanent redirect on the shortened one
When not used in the past 365 days, the shortened URL will not work anymore
Realiability -> the shortened URL must redirect correctly during the active time frame (365 days)
100.000 monthly users
5 URLs shortened per months
-> 500.000 shortened URLs per month
Define what APIs are expected from the system...
We'd need a POST endpoint to create the shortened URL
POST /create -> Body: {url: string} -> response: ok; {url: string; shortenedUrl: string}, error: {url: string, error: string}
The data model is fairly easy, as we just need to keep track of all urls created so far, their shortened versions and the time created.
So there will be a single table called urls with the following fields:
id: int (PK)
url: string
shortened: string
created_at: Date
flowchart TD
n2["Backend Service"];
n3["Redirect Service"];
n5["Frontend Client"];
n6[("Redis")];
n7(("Hosting Service"));
n5 --> n2;
n2 --> n3;
n2 --> n6;
n3 --> n7;
The Frontend Client sends a request to the backend which first checks for the url if it's cached and has a shortened url already. if not it would reach out to a redirect service which creates a temporary redirect in the hosting service (e.g.) cloudflare. It then is written to the cache again from the backend service before the shortened url is returned to the client.
flowchart TD
n2["Backend Service"];
n3["Redirect Service"];
n5["Frontend Client"];
n6[("Redis")];
n7(("Hosting Service"));
subgraph n10["Message Broker"]
end
n5 -->|"sends shortening request"| n2;
n2 --> n3;
n2 -->|"reads / writes"| n6;
n3 -->|"creates a temp redirect"| n7;
n3 -->|"creates message"| n10;
n10 -->|"notifies"| n2;
A message broker is introduced for notification purposes of new redirects being created so the cache can be updated. the backend service has a clear ownership about the redis data and the DB. As the user awaits a response, we don't want to introduce more latency and also a possible failure on the response just because the cache update fails. the redirect service publishes a message to the broker which notifies the backend service and both the cache and DB are updated.
Here is to consider that the message process could fail and then there would be data loss. However as the message is very simple (just a url and it's shortened version) a DLQ with proper monitoring can handle it and write it to the DB as well. This comes with additional complexity but leads the user to almost no failure case and a working state, as the most important thing is the redirect to work, not to be written in the DB or redis, as those are for caching and tracking purposes mainly.
A single Redis instance can be a bottleneck, but for the current scale it should be fine.
Scaling the redis replica counts.