{"id":22879312,"url":"https://github.com/redsoftwaresystems/nodejs-mdp02","last_synced_at":"2025-05-07T22:22:04.633Z","repository":{"id":265580820,"uuid":"885453122","full_name":"RedSoftwareSystems/nodejs-mdp02","owner":"RedSoftwareSystems","description":"Implementation of 0mq Majordomo Pattern 0.2 written in ES6","archived":false,"fork":false,"pushed_at":"2024-11-08T16:02:55.000Z","size":54,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-01T04:43:53.857Z","etag":null,"topics":["zeromq"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RedSoftwareSystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-08T16:02:36.000Z","updated_at":"2024-12-01T11:05:08.000Z","dependencies_parsed_at":"2024-11-30T01:45:48.179Z","dependency_job_id":"12c46729-4fa8-4e87-9534-cd57a85bb108","html_url":"https://github.com/RedSoftwareSystems/nodejs-mdp02","commit_stats":null,"previous_names":["redsoftwaresystems/nodejs-mdp02"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedSoftwareSystems%2Fnodejs-mdp02","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedSoftwareSystems%2Fnodejs-mdp02/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedSoftwareSystems%2Fnodejs-mdp02/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedSoftwareSystems%2Fnodejs-mdp02/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RedSoftwareSystems","download_url":"https://codeload.github.com/RedSoftwareSystems/nodejs-mdp02/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252962852,"owners_count":21832409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["zeromq"],"created_at":"2024-12-13T16:38:51.283Z","updated_at":"2025-05-07T22:22:04.614Z","avatar_url":"https://github.com/RedSoftwareSystems.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MDP02\n\nThis is the implementation of the MDP written in ES6 and relying on [bindings](https://github.com/JustinTulloss/zeromq.node)\nfor node.js and io.js to [ZeroMQ](http://zeromq.org/)\n\n\n\nThe [Majordomo Protocol (MDP)](http://rfc.zeromq.org/spec:18) defines a reliable service-oriented request-reply dialog between a set of client\napplications, a broker and a set of worker applications.  \nMDP covers presence, heartbeating, and service-oriented request-reply processing.  \nThis protocol is ideal for a multiprocess distributed microservice architecture.\n\n![majordomo pattern](https://bitbucket.org/repo/Bqyj5y/images/4203151758-mdp.png)\n\nThe goals of MDP are to\n* Allow requests to be routed to workers on the basis of abstract service names.\n* Allow both peers to detect disconnection of the other peer, through the use of heartbeating.\n* Allow the broker to implement a \"least recently used\" pattern for task distribution to workers for a given service.\n* Allow the broker to recover from dead or disconnected workers by resending requests to other workers.\n\nThis library is ideal for a distributed micro-services architecture where scalability and performance are\nkey features.\n\nBroker, workers and clients, don't require a specific order to start and broker and workers can be\ndisconnected without breaking the request-response process, if the request timeout is respected.\n\n\n## Broker\n\nBroker is the central unit that has the task to dispatch messages between a Client originating a request\nand a Worker that exposes a service and returns a response.  \nA broker can be bound to more than a single socket. The service can be provided by workers connected\nto different end points.\n\n```javascript\nconst broker = makeBroker({\n    bindings: [\n        \"tcp://127.0.0.1:4242\",\n        \"tcp://192.168.100.1:4243\",\n        \"ipc:///tmp/mdp02-01\"\n    ]\n});\n\nbroker.start();\n```\n\n## Worker\n\nWorker is a unit that serves synchronous request-response pairs for a given service.\n\nA service is identified by its name, and a **service may be served by more than a worker**, a worker can serve\nonly a request a time.\n\n```javascript\nconst makeWorker = require('mdp02').makeWorker,\n    fs = require('fs');\n\nconst worker = makeWorker({\n    serviceName: \"fileTransfer\",\n    address: \"tcp://127.0.0.1:4242\"\n});\n\nworker.on('request', function (req) {\n    let response = req.response,\n        readable = fs.createReadStream(req.request.toString()); //no exception handling\n    readable.pipe(response);\n});\n\nworker.start();\n```\n\n## Client\n\nClient is the request originator.  \nClients can execute a request at a time, requests sent are queued into Client internal buffer for sequential execution.  \nOn send method a stream is returned.\n\n```javascript\nconst makeClient = require('mdp02').makeClient,\n    fs = require('fs');\n\nlet helloClient = makeClient({address: \"tcp://127.0.0.1:4242\"}),\n    fileName = path.resolve('remoteFile.txt'),\n    outputFile = fs.createWriteStream('path-to-local-file.txt');\n\nlet response = helloClient.send(\"fileTransfer\", fileName);\n\nresponse.pipe(outputFile);\n\noutputFile.on('finish', function() {\n    helloClient.stop();\n    doSomethingWithLocalFile();\n});\n```\n\n## API\n\n### Broker\n\nBroker can be accessed with:\nconst makeBroker = require('mdp02').makeBroker;\n\n**makeBroker(opts) -\u003e Broker** is a function that returns a Broker instance.\nA Broker is an instance of EventEmitter.\n\n**_opts::Object{bindings, workerTimeout, clientTimeout}_**\n* **bindings(required)**: Array of addresses to which the  Broker will be bound to.\n    ex.: ['tcp://127.0.0.1:3333', 'ipc:///tmp/mdp02-01']\n* **workerTimeout**: (default to 5000 msec) Timeout for which a connected worker\n  is considered stale and unregistered. A disconnect message is sent to the worker,\n  so that the worker will try to automatically disconnect and reconnect to the worker.\n* **clientTimeout**: (default to 5000 msec) Timeout for which a client request is considered expired and removed form the request queue.\n* **hbFrequence**: (default to 1/5 of workerTimeout) Frequence of heart beat, used to check connections with brokers and\nclients ealth.\n#### Worker Methods\n\n * **start** Binds the broker to the given addresses\n * **stop** Disconnects the broker and removes all listeners\n\n#### Broker Events\n\n\u003e name: **'error'**, Event: Error\u003cbr\u003e\nEmitted on erros (soket or protocol errors)\n\n\u003e name: **'request'**, Event::Object{binding, service, command}\u003cbr\u003e\nEmitted when a request comes from a client.\n* Event.binding: the binding address that received the request\n* Event.service: the service name\n* Event.command: the command request\n\n\u003e name: **'worker-connect'**, Event: Object{binding, service}\u003cbr\u003e\nEmitted when a worker is connected to the service pool.\n* Event.binding: the binding address that received the request\n* Event.service: the service name\n\n\n\u003e name: **'worker-ready'**, Event: Object{binding, service}\u003cbr\u003e\nEmitted when a worker is ready to serve a request.\n* Event.binding: the binding address that received the request\n* Event.service: the service name\n\n\u003e name: **'worker-busy'**, Event: Object{binding, service}\u003cbr\u003e\nEmitted when a worker is actually serving a request\n* Event.binding: the binding address that received the request\n* Event.service: the service name\n\n\u003e name: **'worker-disconnect'**, Event: Object{binding, service}\u003cbr\u003e\nEmitted when a worker is going to be disconnected from the broker\n* Event.binding: the binding address that received the request\n* Event.service: the service name\n\n\n### Worker\n\nWorker can be accessed with:\nconst makeWorker = require('mdp02').makeWorker;\n\n**makeWorker(opts) -\u003e Worker** is a function that returns a Worker instance.\nA Worker is an instance of EventEmitter.\n\n**_opts::Object{address, timeout, hbFrequence}_**\n* **address(required)**: The address to use to connect to the Broker.\n    ex.: 'tcp://127.0.0.1:3333'\n* **timeout**: (default to 5000 msec) Timeout for which a broker\n  is considered in stale. A disconnect message is sent to the broker and a restart\n  action is performed.\n* **hbFrequence**: (default to 1/5 of timeout) Frequence of heart beat, used to check connection/broker\nealth.\n\n#### Worker Methods\n\n* **start** Connects the worker to the Broker\n* **stop** Disconnects the worker from the Broker\n\n#### Worker Events\n\n\u003e name: **'error'**, Event: Error\u003cbr\u003e\nEmitted on erros (soket or protocol errors).\n\n\u003e name: **'request'**, Event: Object{response::Stream, request::Buffer|Buffer[]}\u003cbr\u003e\nEmitted when a worker receives a request from a Client through a broker\n* Event.response: a [stream.Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable) used to send the response back\n* Event.request: the request message originated from the client\n\n\u003e name: **'close-request'**, Event: _null_\u003cbr\u003e\nEmitted when the worker has finished sennding back its reply\n\n### Client\n\nClient can be accessed with:\nconst makeWorker = require('mdp02').makeClient;\n\n**makeClient(opts) -\u003e Client** is a function that returns a Client instance.\nA Client enqueue requests for the desired services and obtain responses in the\ngive order.\n\n```javascript\nfunction newClient(address) {\n    return makeClient({\n        address: 'tcp://127.0.0.1:3333'\n    });\n}\n\nfunction makePromise() {\n    return new Promise(function(resolve, reject) {\n        let client = newClient(),\n            response = client.send(\"now\");\n        response.on('data', function(data) {\n            console.log('received', data);\n        });\n\n        response.on('end', function(data) {\n            resolve(parseInt(data, 10));\n        });\n        response.on('error', function(err) {\n            reject(err);\n        });\n    });\n}\n\nlet p1 = makePromise(),\n    p2 = makePromise(),\n    p3 = makePromise();\n\nPromise.all([p1, p2, p3]).then(function (result) {\n    let [r1, r2, r3] = result;\n\n    assert(r1 \u003c r2 \u003c r3, `Resuts not in the correct order ${r1} \u003c ${r2} \u003c ${r3} ===  ${r1 \u003c r2 \u003c r3}`);\n});\n```\n\n* **address(required)**: The address to use to connect to the Broker.\n    ex.: 'tcp://127.0.0.1:3333'\n* **timeout**: (default to 5000 msec) Timeout for which a client\n  is considered in stale. A retry is performed in case.\n* **maxRetries** Number of time ca client can try a request.\nMust be grater than 1 (default is 3). If  the number of tries exceeds this limit\nan error event is emitted and the enqueued requests are discarded\n\n#### Client Properties\n\n\n\n#### Client Methods\n\n\u003e **send(service::String, message::String|Buffer|String[]|Buffer[]) -\u003e [stream.Readable](https://nodejs.org/api/stream.html#stream_class_stream_readable)** Send a request for a service and returns\na stream.Readeable.\n* **service(required)**: The service name to call\n* **message**: The message to send to the desired service. Can be a String, Buffer or an array of strings or buffers.\n\n\u003e **stop** Disconnects the client from the Broker and resets the request queue\n\n1) _workers, clients and broker timeouts should match to avoid false error handling_","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredsoftwaresystems%2Fnodejs-mdp02","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredsoftwaresystems%2Fnodejs-mdp02","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredsoftwaresystems%2Fnodejs-mdp02/lists"}