Skip to content

UltimateProdigy/chronos

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Chronos ⏰

Distributed Fault-Tolerant Cron & Task Execution Engine

Chronos is a distributed task scheduler built from scratch using Java (for the coordinator leader and Hashed Wheel Timer queue) and TypeScript (for the task executor worker nodes). It achieves ultra-precise timing execution at scale by replacing slow database polling loops with memory-efficient time-wheel algorithms.


📖 Chronos in Plain English (Layman's Terms)

In large systems, you often need to run tasks at specific times—for example, sending subscription renewal emails at midnight, executing weekly bank reports, or running cleaning scripts every 10 minutes.

Normally, a scheduler checks a database every second to see if a job is due (SELECT * FROM jobs WHERE trigger_time <= NOW()). When there are millions of tasks, this constant database querying crashes the database.

Chronos solves this using a two-part architecture:

  1. The Hashed Wheel Timer (Java Coordinator): Think of this as a clock face with 512 ticks. Instead of checking a database, Chronos reads upcoming jobs and maps them onto specific slots on the clock wheel based on their trigger times. When the "second hand" ticks to a slot, Chronos dispatches all tasks in that slot instantly ($O(1)$ efficiency).
  2. Distributed Worker Nodes (TypeScript): Independent worker processes connect to the coordinator over TCP. When a task fires, the coordinator load-balances it, streaming the payload to a registered worker over a raw network connection.
  3. Fault Tolerance: If a worker node crashes mid-execution, the coordinator detects the connection drop, pulls the task back, and reschedules it for execution on another healthy worker (guaranteeing at-least-once task execution).

📂 Project Structure

chronos/
├── worker/                  <-- TypeScript task execution agent
│   ├── src/
│   │   └── worker.ts        <-- TCP socket listener & frame decoder
│   ├── package.json
│   └── tsconfig.json
│
├── scheduler/               <-- Java task coordinator / scheduler
│   ├── src/
│   │   └── main/
│   │       └── java/
│   │           └── com/
│   │               └── chronos/
│   │                   ├── SchedulerServer.java <-- TCP socket gateway & demo task pool
│   │                   ├── TaskJob.java         <-- Task entity inside the wheel
│   │                   └── HashedWheelTimer.java <-- O(1) circular tick queue
│   └── pom.xml              <-- Maven compilation properties
│
├── package.json            <-- Monorepo workspaces coordinator
└── README.md               <-- You are here!

⚙️ Requirements

  • Java JDK 17 (Ensure java and javac are in your PATH)
  • Node.js (v20+ or Bun runtime)
  • Git

🚀 How to Run the Cluster

Follow these steps to start the scheduler, connect a worker node, and witness the real-time execution flow:

1. Compile & Start the Java Coordinator (Terminal 1)

Compile the Java coordinator source files, and start the TCP scheduler:

cd scheduler
mkdir -p target/classes
javac -d target/classes src/main/java/com/chronos/*.java
java -cp target/classes com.chronos.SchedulerServer

2. Start a TypeScript Task Worker Node (Terminal 2)

In a second window, start the executor worker:

cd worker
npm run dev

You will see the worker successfully register in Terminal 1! 🔌 Worker node registered: /127.0.0.1:52134 (Total active: 1)

3. Verify Scheduled Executions

  • Once both processes are active, the coordinator starts scheduling demo tasks to run 2 seconds in the future: ⏰ Scheduled task [job-id-1] to run in 2 seconds.
  • Watch the Hashed Wheel Timer tick. After exactly 2 seconds, the timer fires, and the task payload streams to the worker: 🔀 Dispatched task [job-id-1] to worker: /127.0.0.1:52134
  • Watch Terminal 2. The worker immediately receives the payload, executes the job operations, and logs completion: 📥 [Received] Task Triggered: [job-id-1] ✅ [Success] Task [job-id-1] execution complete. Duration: 642ms

🧪 Testing Fault Tolerance (Worker Failover)

  1. Start the Java Coordinator.
  2. Open two separate terminals and start two workers: npx tsx src/worker.ts in each.
  3. Observe the coordinator round-robin load-balancing task dispatches between both worker nodes.
  4. Kill one of the workers (Ctrl+C) mid-run.
  5. Notice that the coordinator instantly catches the socket disconnection and securely handles job re-routing.

About

A distributed cron and task scheduler utilizing a Hashed Wheel Timer in Java and TCP keep-alive workers in TypeScript.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors