Advertisement
varun1729

Untitled

Apr 15th, 2023
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.03 KB | None | 0 0
  1. const express = require('express');
  2. const bodyParser = require('body-parser');
  3. const uuid = require('uuid');
  4.  
  5. // Define the states for the Raft node
  6. const STATES = {
  7. FOLLOWER: 'FOLLOWER',
  8. CANDIDATE: 'CANDIDATE',
  9. LEADER: 'LEADER',
  10. };
  11.  
  12. class RaftNode {
  13. constructor(port) {
  14. this.nodeId = uuid.v4();
  15. this.port = port;
  16. this.state = STATES.FOLLOWER;
  17. this.currentTerm = 0;
  18. this.votedFor = null;
  19. this.voteCount = 0;
  20. this.peers = [];
  21. this.app = express();
  22. this.app.use(bodyParser.json());
  23.  
  24. // Define the /vote endpoint for receiving vote requests
  25. this.app.post('/vote', (req, res) => {
  26. const { term, candidateId } = req.body;
  27.  
  28. // If the received term is greater than the current term, update the current term and reset the votedFor field
  29. if (term > this.currentTerm) {
  30. this.currentTerm = term;
  31. this.votedFor = null;
  32. }
  33.  
  34. // If the node has not voted for any candidate in this term and the candidateId matches the received ID, grant the vote
  35. if (this.votedFor === null && candidateId === this.candidateId) {
  36. this.votedFor = candidateId;
  37. this.state = STATES.FOLLOWER;
  38. clearTimeout(this.candidateTimeout);
  39. this.setFollowerTimeout();
  40. res.status(200).json({ voteGranted: true });
  41. } else {
  42. // Otherwise, deny the vote
  43. res.status(200).json({ voteGranted: false });
  44. }
  45. });
  46.  
  47. // Start the Express app
  48. this.app.listen(this.port, () => {
  49. console.log(`Raft Node ${this.nodeId} running on port ${this.port}`);
  50. });
  51.  
  52. // Start the initial timer as a follower
  53. this.setFollowerTimeout();
  54. }
  55.  
  56. // Register the peer nodes
  57. registerPeers(peers) {
  58. this.peers = peers;
  59. }
  60.  
  61. // Set a random timeout to become a candidate
  62. setFollowerTimeout() {
  63. this.candidateTimeout = setTimeout(() => {
  64. this.state = STATES.CANDIDATE;
  65. this.currentTerm++;
  66. this.voteCount = 1;
  67. this.votedFor = this.nodeId;
  68. this.requestVotes();
  69. }, Math.floor(Math.random() * (3000 - 1500)) + 1500);
  70. }
  71.  
  72. // Request votes from all other nodes
  73. async requestVotes() {
  74. const requestOptions = {
  75. method: 'POST',
  76. headers: { 'Content-Type': 'application/json' },
  77. body: JSON.stringify({ term: this.currentTerm, candidateId: this.nodeId }),
  78. };
  79.  
  80. const promises = this.peers.map(peer =>
  81. fetch(`http://${peer}/vote`, requestOptions)
  82. .then(response => response.json())
  83. .then(data => {
  84. if (data.voteGranted) {
  85. this.voteCount++;
  86. }
  87. })
  88. .catch(err => console.error(`Error requesting vote from ${peer}: ${err}`))
  89. );
  90.  
  91. await Promise.all(promises);
  92. this.evaluateElection();
  93. }
  94.  
  95. // Check if the node has received a majority of votes and become the leader
  96. evaluateElection() {
  97. if (this.state === STATES.CANDIDATE && this.voteCount > this.peers.length / 2) {
  98. this.state = STATES.LEADER;
  99. console.log(`Node ${this.nodeId} became the leader of term ${this.currentTerm}`);
  100. } else {
  101. this.setFollowerTimeout();
  102. }
  103. }
  104. }
  105.  
  106. // Create an array of 5 nodes and register their peers
  107. const nodes = [];
  108. for (let i = 0; i < 5; i++) {
  109. const node = new RaftNode(3000 + i);
  110. nodes.push(node);
  111. }
  112. nodes.forEach(node => node.registerPeers(nodes.map(n => `localhost:${n.port}`)));
  113. This code creates an array of 5 RaftNode instances with ports ranging from 3000 to 3004. Each node registers all other nodes as peers using the registerPeers method. When a node becomes a candidate, it sends a POST request to the /vote endpoint of all other nodes with its current term and ID. Each node checks if it has already voted in this term and if not, grants the vote to the candidate if its ID matches the received ID. If a candidate receives a majority of the votes, it becomes the leader and prints a message to the console. If a candidate does not receive a majority of the votes, it resets its follower timer and starts over as a follower
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement