/compassion

Paxos based consensus framework.

Primary LanguageJavaScriptMIT LicenseMIT

Actions Status codecov License: MIT

Paxos based consensus framework.

What Where
Discussion #1
Documentation https://bigeasy.github.io/compassion
Source https://github.com/bigeasy/compassion
Issues https://github.com/bigeasy/compassion/issues
CI https://travis-ci.org/bigeasy/compassion
Coverage: https://codecov.io/gh/bigeasy/compassion
License: MIT

Compassion installs from NPM.

npm install compassion

Living README.md

This README.md is also a unit test using the Proof unit test framework. We'll use the Proof okay function to assert out statements in the readme. A Proof unit test generally looks like this.

require('proof')(4, async okay => {
    okay('always okay')
    okay(true, 'okay if true')
    okay(1, 1, 'okay if equal')
    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')
})

You can run this unit test yourself to see the output from the various code sections of the readme.

git clone git@github.com:bigeasy/compassion.git
cd compassion
npm install --no-package-lock --no-save
node test/readme.t.js

Overview

const Compassion = require('compassion')
const Destructible = require('destructible')
const { Queue } = require('avenue')
class KeyValueStore {
    constructor () {
        this.ready = new Promise(resolve => this.arrived = resolve)
        this.cookie = 0
        this.snapshots = {}
        this.resolutions = {}
        this.compassion = null
        this.store = null
    }

    initialize (compassion) {
        this.compassion = compassion
    }

    async bootstrap ({ self }) {
        this.promise = self.arrived
        this.store = {}
    }

    async snapshot ({ promise, queue }) {
        queue.push(this.snapshots[promise])
    }

    async join ({ self, shifter }) {
        this.promise = self.arrived
        this.store = await shifter.shift()
    }

    async arrive ({ arrival }) {
        this.arrived.call()
        this.snapshots[arrival.promise] = JSON.parse(JSON.stringify(this.store))
    }

    async acclimated ({ promise }) {
        this.snapshots[promise]
    }

    async entry ({ entry }) {
        this.store[entry.key] = entry.value
        const resolution = this.resolutions[entry.cookie]
        if (resolution != null) {
            delete this.resolutions[entry.cookie]
            resolution.call(null)
        }
    }

    async depart ({ promise }) {
        this.snapshots[promise]
    }

    set (key, value) {
        return new Promise(resolve => {
            const cookie = `${this.promise}?${this.cookie++}`
            this.resolutions[cookie] = resolve
            this.compassion.enqueue({ cookie, key, value })
        })
    }

    get (key) {
        return this.store[key]
    }
}
const destructible = new Destructible('compassion')

Construct a census. Usually you'll use Mingle, but we'll create a dummy census and fake the service discovery. We have to be sure to terminate the queue on shutdown, so we register a destruct handler.

const census = new Queue
destructible.destruct(() => census.push(null))
const kv = new KeyValueStore
const { address, port } = await Compassion.listen(destructible, {
    census: census.shifter(),
    applications: { kv },
    bind: { host: '127.0.0.1', port: 0 }
})
census.push([ `http://${address}:${port}` ])

await kv.ready
await kv.set('x', 1)
okay(kv.get('x'), 1, 'set and get')
destructible.destroy()

await destructible.promise

What do we need to discuss? Simple outline. Be sure to link to people to Conference. Uh, oh. I also have to document Mingle.

Initialize

Bootstrap

Join and Snapshot

Arrive

Acclimated

Entry

Depart