node-raft-redis
TypeScript icon, indicating that this package has built-in type declarations

0.1.1 • Public • Published

Consensus for node microservices, based on a simplified version of the raft algorithm. Requires redis as a medium. Features automatic discovery of the services of same kind. Selects one instance of a microservice as leader. For example, the leader can push jobs to a redis queue while the followers process them.


Usage:

import { Candidate } from "./index";

const candidate = new Candidate({
  redis: {
    host: "localhost",
    port: 6379,
    // or url: 'redis://alice:foobared@awesome.redis.server:6380'
  },
  kind: "my-service",
});

candidate.on("elected", () => {
  console.log("elected");
  // You can be sure only this instance is the leader (at the moment).

  candidate.messageFollowers("Hello from leader");

  // The leader can start a re-election with reelect()
  // It is possible for this instance to be elected again. In that case, "elected" will be emitted again.
  // candidate.reelect();
});

candidate.on("defeated", (leader) => {
  console.log(`defeated by the new leader ${leader}`)
  candidate.messageLeader("Hello from your new follower")
});

candidate.on("message", ({ message, from }) => {
  console.log(`Got message ${message} from ${from}`)
});

candidate.on("error", (err) => {
  console.error(err);
});

candidate.start();

Examples:

const candidate = new Candidate({
  redis: {
    host: "localhost",
    port: 6379,
  },
  kind: "my-service",
  meta: {
    // Set some metadata for this instance
    someKey: Math.random(),
  },
});

await candidate.start();
// Get all instances of this kind, including self
const instances = await candidate.getInstances()
/*
[
  {
    id: 'rqcpc6g0ncgi3mxtysyv1',
    meta: { someKey: 0.8191968688804481 },
    state: 'follower'
  },
  {
    id: 'ga4empryhsch6mi5zlemgn',
    meta: { someKey: 0.5482506611623577 },
    state: 'follower'
  },
  {
    id: 'qtualcg9ncgq62eruoqe18',
    meta: { someKey: 0.6551732192131019 },  
    state: 'leader'
  },
  {
    id: 'aow8uegf3241mt95pqhte3',
    meta: { someKey: 0.7014849186816583 },  
    state: 'follower'
  }
]
*/

// Send a message to an instance
candidate.messageTo('rqcpc6g0ncgi3mxtysyv1', "Hello")

// Send a message to all instances
candidate.messageAll("Hello")

// Send a message to the follower instances
candidate.messageFollowers("Hello from leader")

// Send a message to the leader
candidate.messageLeader("Hello from follower")

// Get the instance's metadata
const meta = candidate.getMeta()

// Change the instance's metadata
await candidate.setMeta({
  someKey: "someValue"
})
candidate.on("message:from:leader", ({ message, from }) => {
// Will be logged only in the follower instances.
  console.log(`Got message ${message} from the leader instance ${from}`);
});

candidate.on("message:from:follower", ({ message, from }) => {
  // Will be logged only in the leader instance.
  console.log(`Got message ${message} from the follower instance ${from}`);
});
candidate.on("message", async ({ message, from }) => {
  const currentLeader = await candidate.getLeader();
  const isFromLeader = from === currentLeader.id;
  
  if (isFromLeader) {
    console.log(`Got message ${message} from the leader instance ${from}`);
    candidate.messageTo(from, "Echo from follower");
    // candidate.messageLeader("Echo from follower"); <- same thing in this specific case
  } else {
    console.log(`Got message ${message} from the follower instance ${from}`);
  }
});

Methods (all async):

  • start: connects to redis, starts the candidate's internal processes
  • stop: disconnects from redis, stops the candidate's internal processes
  • reelect: if the candidate is the leader, starts a re-election
  • messageFollowers: send message to the followers
  • messageLeader: send message to the leader
  • messageTo: send a message to the specific instance
  • messageAll: send a message to all of the instances
  • getInstances: get the instances of this kind along with their metadata
  • setMeta: set the current instance's metadata

Properties:

  • id: the current instance's unique generated ID
  • state: "follower" | "candidate" | "leader"
  • currentTerm: number
  • meta: the current instance's metadata

Events:

  • elected: emitted on the following state transitions:
    1. candidate -> leader
  • defeated: emitted on the following state transitions:
    1. leader -> follower
    2. candidate -> follower
  • message: message from the leader or the followers
  • message:from:follower: message from the followers
  • message:from:leader: message from the leader
  • statechange: on state transition
  • error: redis connection error

Package Sidebar

Install

npm i node-raft-redis

Weekly Downloads

2

Version

0.1.1

License

ISC

Unpacked Size

44.2 kB

Total Files

10

Last publish

Collaborators

  • nitedani