Users can schedule recurring tasks with different possible recurring frequency for example, every day, every week, every year etc.
Users can also set the time of a task
Users can add sub-tasks to a task
Users can set the priority of a task
Users can add notes to a task
Users will receive a notification when the task is due
Users should be able to make their own profile and store their task there
Non-Functional
Scalability
Service should be able to handle a growing user base with more to be added in the future
Reliability
Tasks should be stored reliably and never be lost
Data should be replicated multiple times over to provide redundancy
Latency
Notification for tasks should arrive promptly and not be late
Notification should be sent no matter what
Capacity Estimation
We assume we deal with 1 million daily active users
We assume that each user creates 10 tasks on average every day
In a day, we create 10^6 * 10 = 10^7 tasks every day
We assume each task needs 1 KB data
Thus, amount of data generated in a day would be 10^10 bytes = 10 GB
Over a month, we would need 300 GB data
Over a year we would need 3600 GB data or 3.6 PB
Over 10 years we would need 36 PB data
Factoring in redundancy we would need roughly 200 PB data over 10 years
API Design
/tasks/create
POST
Takes in a JSON as arguments which would describe the task, its title, frequency if it reoccurs, description, sub-tasks, due date etc.
Returns the unique task ID
/tasks/update
PUT
Takes in a JSON as argument and updates a previously created task
Returns success in case the task is updated, error otherwise
/tasks/cancel
DELETE
Removes the specified task
/tasks/read
GET
Returns the description of a task
Database Design
Consistency is important when executing tasks accurately, thus, we go with a relational database
classDiagram
class tasks {
taskID
userID
executionDataTime
recurringPeriod
description
priority
}
High-Level Design
Scheduler service stores tasks in a relational database
Task Runner reads the stored tasks and in case a notification needs to be sent, it adds a notification to be sent to a user in a message queue which is then sent to the user
Email sender takes in the message from the queue and sends en email to the user
Request Flows
Detailed Component Design
We can have a priority queue where the priority of a task is based on the time of a task, a task for which a notification needs to be sent next has the highest priority
We can keep checking the top of the queue against the current time, if the current time matches that on the message at the top of the queue, we trigger a notification
Trade Offs/Tech Choices
For the relational database, we use PostgreSQL
For our message queue, we use Apache Kafka
We do not choose a non-relational database since relational databases provide better consistency
Failure Scenarios/Bottlenecks
Notification or payment fails. Retry N times using the Message Queue. After that, notify the user of failure.