{"id":13468531,"url":"https://github.com/dashersw/cote","last_synced_at":"2025-05-13T16:08:34.712Z","repository":{"id":37432306,"uuid":"9730421","full_name":"dashersw/cote","owner":"dashersw","description":"A Node.js library for building zero-configuration microservices.","archived":false,"fork":false,"pushed_at":"2024-11-16T01:35:51.000Z","size":1613,"stargazers_count":2379,"open_issues_count":46,"forks_count":187,"subscribers_count":59,"default_branch":"master","last_synced_at":"2025-05-09T15:38:12.233Z","etag":null,"topics":["high-availability","javascript","microservice","microservices","nodejs","scalability","zero-configuration"],"latest_commit_sha":null,"homepage":"http://cote.js.org","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/dashersw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2013-04-28T13:35:48.000Z","updated_at":"2025-04-24T20:46:42.000Z","dependencies_parsed_at":"2024-06-13T06:39:26.723Z","dependency_job_id":"e7cbb13f-ebfc-40e1-a0a0-59735b142cbc","html_url":"https://github.com/dashersw/cote","commit_stats":{"total_commits":336,"total_committers":23,"mean_commits":"14.608695652173912","dds":"0.14880952380952384","last_synced_commit":"5138889f3bfd4a7e524b66d95c6bb505b6d41fbb"},"previous_names":[],"tags_count":95,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dashersw%2Fcote","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dashersw%2Fcote/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dashersw%2Fcote/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dashersw%2Fcote/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dashersw","download_url":"https://codeload.github.com/dashersw/cote/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253331001,"owners_count":21891849,"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":["high-availability","javascript","microservice","microservices","nodejs","scalability","zero-configuration"],"created_at":"2024-07-31T15:01:12.940Z","updated_at":"2025-05-13T16:08:29.703Z","avatar_url":"https://github.com/dashersw.png","language":"JavaScript","readme":"![cote](https://user-images.githubusercontent.com/698308/32996603-1517088a-cd85-11e7-85c5-8ef9b3ae2e49.png)\n\ncote — A Node.js library for building zero-configuration microservices\n====\n\n[![npm version](https://badge.fury.io/js/cote.svg)](https://badge.fury.io/js/cote)\n[![Build Status](https://travis-ci.org/dashersw/cote.svg?branch=master)](https://travis-ci.org/dashersw/cote)\n[![Coverage Status](https://coveralls.io/repos/github/dashersw/cote/badge.svg)](https://coveralls.io/github/dashersw/cote)\n[![dependencies Status](https://david-dm.org/dashersw/cote/status.svg)](https://david-dm.org/dashersw/cote)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dashersw/cote/master/LICENSE)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fdashersw%2Fcote.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fdashersw%2Fcote?ref=badge_shield)\n\n**cote lets you write zero-configuration microservices in Node.js without nginx,\nhaproxy, redis, rabbitmq or _anything else_. It is batteries — and chargers! —\nincluded.**\n\nJoin us on\n[![cote Slack](http://slack.cotejs.org/badge.svg)](http://slack.cotejs.org)\nfor anything related to cote.\n\n## Features\n- **Zero dependency:** Microservices with only JavaScript and Node.js\n- **Zero-configuration:** No IP addresses, no ports, no routing to configure\n- **Decentralized:** No fixed parts, no \"manager\" nodes, no single point of\n                     failure\n- **Auto-discovery:** Services discover each other without a central bookkeeper\n- **Fault-tolerant:** Don't lose any requests when a service is down\n- **Scalable:** Horizontally scale to any number of machines\n- **Performant:** Process thousands of messages per second\n- **Humanized API:** Extremely simple to get started with a reasonable API!\n\nDevelop your first microservices in under two minutes:\n----\nin `time-service.js`...\n```js\nconst cote = require('cote');\nconst timeService = new cote.Responder({ name: 'Time Service' });\n\ntimeService.on('time', (req, cb) =\u003e {\n    cb(new Date());\n});\n```\n\nin `client.js`...\n```js\nconst cote = require('cote');\nconst client = new cote.Requester({ name: 'Client' });\n\nclient.send({ type: 'time' }, (time) =\u003e {\n    console.log(time);\n});\n```\n\nYou can run these files anyway you like — on a single machine or scaled out to\nhundreds of machines in different datacenters — and they will *just work*. No\nconfiguration, no third party components, no nginx, no kafka, no consul and\n**only** Node.js. cote is batteries — and chargers — included!\n\nMicroservices case study\n----\nMake sure to check out\n[the e-commerce case study](https://github.com/dashersw/cote-workshop) that\nimplements a complete e-commerce application with microservices using\n[cote](https://github.com/dashersw/cote). It features;\n\n+ a back-office with real-time updates for managing the catalogue of products\nand displaying sales with a RESTful API (express.js)\n+ a storefront for end-users with real-time updates to products where they\ncan buy the products with WebSockets (socket.io)\n+ a user microservice for user CRUD\n+ a product microservice for product CRUD\n+ a purchase microservice that enables users to buy products\n+ a payment microservice that deals with money transactions that occur as\na result of purchases\n+ Docker compose configuration for running the system locally\n\ncote plays very well with Docker, taking advantage of its network overlay\nfeatures. The case study implements a scalable microservices application\nvia Docker and can scale to multiple machines.\n\n## Table of Contents\n1. [Motivation](#motivation)\n1. [Getting started](#getting-started)\n    1. [Introduction to cote](#introduction-to-cote)\n    1. [Installation](#installation)\n    1. [Using cote for the first time](#using-cote-for-the-first-time)\n    1. [Implementing a request-response mechanism](#implementing-a-request-response-mechanism)\n        1. [Creating a requester](#creating-a-requester)\n        1. [Creating a responder](#creating-a-responder)\n    1. [Tracking changes in the system with a publish-subscribe mechanism](#tracking-changes-in-the-system-with-a-publish-subscribe-mechanism)\n        1. [Creating the arbitration service](#creating-the-arbitration-service)\n        1. [Creating a publisher](#creating-a-publisher)\n        1. [Creating a subscriber](#creating-a-subscriber)\n1. [Components Reference](#components-reference)\n    1. [Requester](#requester)\n    1. [Responder](#responder)\n    1. [Publisher](#publisher)\n    1. [Subscriber](#subscriber)\n    1. [Sockend](#sockend)\n    1. [Monitor](#monitor)\n    1. [Monitoring Tool](#monitoring-tool)\n1. [Advanced Usage](#advanced-usage)\n    1. [Environments](#environments)\n    1. [Keys](#keys)\n    1. [Namespaces](#namespaces)\n    1. [Multicast address](#multicast-address)\n    1. [Broadcast address](#broadcast-address)\n    1. [Controlling cote with environment variables](#controlling-cote-with-environment-variables)\n1. [Deploying with Docker Cloud](#deploying-with-docker-cloud)\n1. [Using centralized discovery tools](#using-centralized-discovery-tools)\n1. [FAQ](#faq)\n1. [Contribution](#contribution)\n1. [License](#mit-license)\n\nMotivation\n----\n\nTomorrow belongs to ~~distributed software~~ microservices.\nAs CPU performance is heavily dictated by the number of cores and the power of\neach core is already at its limits, distributed computing will decide how your\napplication performs. ~~Distributed systems~~ Microservices also pose great\narchitectural benefits such as fault-tolerance and scalability.\n\nComponents of such ~~a distributed system~~ microservices should be able to\nfind other components\n\u003ca href=\"http://en.wikipedia.org/wiki/Zero_configuration_networking\"\u003e\nzeroconf\u003c/a\u003e and communicate over a set of conventions. Sometimes they may work\nas a cluster, may include a pub/sub mechanism, or a request/response mechanism.\n\ncote brings you all the advantages of ~~distributed software~~ microservices.\nThink of it like homing pigeons.\n\nGetting Started\n----\n\n### Introduction to cote\n\ncote allows you to implement hassle-free microservices by utilizing\nauto-discovery and other techniques. Typically, in a microservices system, the\napplication is broken into smaller chunks that communicate with each other.\ncote helps you build such a system by providing you several key components\nwhich you can use for service communication.\n\nIn a way, cote is the glue that's most necessary between different\nmicroservices. It replaces queue protocols and service registry software by\nclever use of IP broadcast/IP multicast systems. It's like your computer\ndiscovering there's an Apple TV nearby. This means, cote needs an\nenvironment that allows the use of IP broadcast or multicast, in order to\nscale beyond a single machine. Most bare-metal systems are designed this way,\nhowever, cloud infrastructure like AWS needs special care, either an overlay\nnetwork like Weave, or better yet, just, Docker — which is fortunately the way\nrun all of our software today anyway. That's why Docker is especially important\nfor cote, as it enables cote to work its magic.\n\ncote also replaces HTTP communication. Microservices architecture is meant for\nhundreds of internal services communicating with each other. That being the\ncase, a protocol like HTTP is cumbersome and heavy for communication that\ndoesn't need 90% of HTTP's features. Therefore, cote uses a very light protocol\nover plain old TCP sockets for communication, making it fast, effective and\nmost importantly, cheap.\n\n### Installation\n\ncote is a Node.js library for building microservices applications. It's\navailable as an [npm package](https://npmjs.org/package/cote).\n\nInstall cote locally via npm:\n\n```bash\nnpm install cote\n```\n\n### Using cote for the first time\n\nWhether you want to integrate cote with an existing web application — e.g.\nbased on express.js as exemplified\n[here](https://github.com/dashersw/cote-workshop/blob/master/admin/server.js)\n— or you want to rewrite a portion of your monolith, or you want to rewrite a\nfew microservices with cote, all you need to do is to instantiate a few of\ncote's components (e.g. [Responder](#responder), [Requester](#requester),\n[Publisher](#publisher), [Subscriber](#subscriber)) depending on\nyour needs, and they will start communicating automatically. While one component\nper process might be enough for simple applications or for tiny microservices, a\ncomplex application would require close communication and collaboration of\nmultiple microservices. Hence, you may instantiate multiple components in a\nsingle process / service / application.\n\n### Implementing a request-response mechanism\n\nThe most common scenario for applications is the request-response cycle.\nTypically, one microservice would request a task to be carried out or make\na query to another microservice, and get a response in return. Let's implement\nsuch a solution with cote.\n\nFirst, require cote;\n\n```js\nconst cote = require('cote');\n```\n\n#### Creating a requester\n\nThen, instantiate any component you want. Let's start with a `Requester` that\nshall ask for, say, currency conversions. `Requester` and all other components\nare classes on the main `cote` object, so we instantiate them with the `new`\nkeyword.\n\n```js\nconst requester = new cote.Requester({ name: 'currency conversion requester' });\n```\n\nAll cote components require an object as the first argument, which should at\nleast have a `name` property to identify the component. The name is used mainly\nas an identifier in monitoring components, and it's helpful when you read the\nlogs later on as each component, by default, logs the name of the other\ncomponents they discover.\n\n`Requester`s send requests to the ecosystem, and are expected to be used\nalongside `Responder`s to fulfill those requests. If there are no `Responder`s\naround, a `Requester` will just queue the request until one is available. If\nthere are multiple `Responder`s, a `Requester` will use them in a round-robin\nfashion, load-balancing among them.\n\nLet's create and send a `convert` request, to ask for conversion from USD into\nEUR.\n\n```js\nconst request = { type: 'convert', from: 'usd', to: 'eur', amount: 100 };\n\nrequester.send(request, (err, res) =\u003e {\n  console.log(res);\n});\n```\n\nYou can save this file as `client.js` and run it via `node client.js`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\n    Click to see the complete \u003ccode\u003eclient.js\u003c/code\u003e file.\n\u003c/summary\u003e\n\u003cp\u003e\n\n```js\nconst cote = require('cote');\n\nconst requester = new cote.Requester({ name: 'currency conversion requester'});\n\nconst request = { type: 'convert', from: 'usd', to: 'eur', amount: 100 };\n\nrequester.send(request, (err, res) =\u003e {\n  console.log(res);\n});\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\nNow this request will do nothing, and there won't be any logs in the console,\nbecause there are no components to fulfill this request and produce a response.\n\nKeep this process running, and let's create a `Responder` to respond to currency conversion requests.\n\n#### Creating a responder\n\nWe first instantiate a `Responder` with the `new` keyword.\n\n```js\nconst responder = new cote.Responder({ name: 'currency conversion responder' });\n```\n\nAs detailed in [Responder](#responder), each `Responder` is also an instance of\n`EventEmitter2`. Responding to a certain request, let's say `convert`, is the\nsame as listening to the `convert` event, and handling it with a function that\ntakes two parameters: a request and a callback. The request parameter holds\ninformation about a single request, and it's basically the same `request` object\nthe requester above sent. The second parameter, the callback, expects to be\ncalled with the actual response.\n\nHere's how a simple implementation might look like.\n\n```js\nconst rates = { usd_eur: 0.91, eur_usd: 1.10 };\n\nresponder.on('convert', (req, cb) =\u003e {\n    cb(null, req.amount * rates[`${req.from}_${req.to}`]);\n});\n```\n\nNow you can save this file as `conversion-service.js` and run it via\n`node conversion-service.js` on a separate terminal.\n\n\u003cdetails\u003e\n\u003csummary\u003e\n    Click to see the complete \u003ccode\u003econversion-service.js\u003c/code\u003e file.\n\u003c/summary\u003e\n\u003cp\u003e\n\n```js\nconst cote = require('cote');\n\nconst responder = new cote.Responder({ name: 'currency conversion responder' });\n\nconst rates = { usd_eur: 0.91, eur_usd: 1.10 };\n\nresponder.on('convert', (req, cb) =\u003e {\n    cb(null, req.amount * rates[`${req.from}_${req.to}`]);\n});\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\nAs you run the service, you will immediately see the first request in\n`client.js` being fulfilled and logged to the console. Now you can take this\nidea and build your services on it.\n\nNotice how we didn't have to configure IP addresses, ports, hostnames, or\nanything else.\n\n\u003e Note: By default, every `Requester` will connect to every `Responder` it\ndiscovers, regardless of the request type. This means, every `Responder` should\nrespond to the exact same set of requests, because `Requester`s will\nload-balance requests between all connected `Responder`s regardless of\ntheir capabilities, i.e, whether or not they can handle a given request.\n\nIf you have multiple `Responder`s with varying response handlers, you will\nexperience lost requests. In cote, this separation between responsibilities is\ncalled segmentation, or partitioning. If you wish to segment your requests in\ngroups, you can use `key`s. Check out [keys](#keys) for a detailed guide on how\nand when to use segmentation.\n\n### Tracking changes in the system with a publish-subscribe mechanism\n\nOne of the benefits of a microservices approach is its ease of use as a tool for\ntasks that previously required serious infrastructural investments. Such a task\nis managing updates and tracking changes in a system. Previously, this required\nat least a queue infrastructure with fanout, and scaling and managing this\ntechnological dependency would be a hurdle on its own.\n\nFortunately, cote solves this problem in a very intuitive and almost magical\nway.\n\nSay, we need an arbitration service in our application which decides currency\nrates, and whenever there's a change within the system, it should notify all the\ninstances of conversion services, so that they facilitate the new values.\n\nOf course, the arbitration service would be API driven, and would receive the\nnew rates over another request so that for example an admin can enter the values\nthrough a back office application. The arbitration service should take this\nupdate and basically forward it to every conversion service. In order to achieve\nthis, the arbitration service should have two components: one `Responder` for\nthe API updates and one `Publisher` for notifying the conversion services. In\naddition to this, the conversion services should be updated to include a\n`Subscriber`. Let's see this in action.\n\n\n#### Creating the arbitration service\n\nA simple implementation of such a service would look like the following. First,\nwe require cote and instantiate a responder for the API. Since we now have two\nresponders, `arbitration API` and `currency conversion responder`, we need to\nintroduce service segmentation by using `key` property. If we had no keys in\nour examples, some requests from our `client.js` would end up in\n`currency conversion responder` and we would get a correct response, but some\nother requests would end up in `arbitration API`, and since arbitration\nresponder isn't listening to `'convert'` events, the request would remain\n unanswered.\n\n`arbitration-service.js`\n\n```js\nconst cote = require('cote');\n\nconst responder = new cote.Responder({ name: 'arbitration API', key: 'arbitration' });\n```\n\nLet's say we keep the rates in a local variable. This could just as well be a\ndatabase call, but for the sake of simplicity let's keep this local.\n\n```js\nconst rates = {};\n```\n\nNow the responder shall respond to an `rate updated` request, allowing admins to\nupdate it from a back office application. The backoffice integration isn't\nimportant at this moment, but [here is an example how back offices could\ninteract with cote responders in the backend](https://github.com/dashersw/cote-workshop/tree/master/admin).\nBasically, this service should have a responder to take in the new rates for a\ncurrency exchange.\n\n```js\nresponder.on('update rate', (req, cb) =\u003e {\n    rates[req.currencies] = req.rate; // { currencies: 'usd_eur', rate: 0.91 }\n\n    cb(null, `changed ${req.currencies} rate to ${req.rate}`);\n});\n```\n\n#### Creating a publisher\n\nWe now have the rates, but the rest of the system, namely, the conversion\nservices aren't aware of this change yet. In order to update them of the\nchanges, we should create a `Publisher`.\n\n```js\nconst publisher = new cote.Publisher({ name: 'arbitration publisher' });\n```\n\nNow whenever there's a new rate, we should utilize this `Publisher`. The\n`update rate` handler thus becomes:\n\n```js\nresponder.on('update rate', (req, cb) =\u003e {\n    rates[req.currencies] = req.rate;\n\n    cb(null, `changed ${req.currencies} rate to ${req.rate}`);\n\n    publisher.publish('rate updated', req);\n});\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\n    Click to see the complete \u003ccode\u003earbitration-service.js\u003c/code\u003e file.\n\u003c/summary\u003e\n\u003cp\u003e\n\n```js\nconst cote = require('cote');\n\nconst responder = new cote.Responder({ name: 'arbitration API', key:'arbitration' });\nconst publisher = new cote.Publisher({ name: 'arbitration publisher' });\n\nconst rates = {};\n\nresponder.on('update rate', (req, cb) =\u003e {\n    rates[req.currencies] = req.rate;\n\n    cb(null, `changed ${req.currencies} rate to ${req.rate}`);\n\n    publisher.publish('rate updated', req);\n});\n\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\nSince currently there are no subscribers in this system, nobody will be notified\nof these changes. In order to facilitate this update mechanism, we need to go\nback to our `conversion-service.js` and add a `Subscriber` to it.\n\n#### Creating a subscriber\n\nA `Subscriber` is a regular cote component, so we instantiate it with the\nfollowing:\n\n```js\nconst subscriber = new cote.Subscriber({ name: 'arbitration subscriber' });\n```\n\nPut this line in `conversion-service.js`.\n\n`Subscriber` also extends `EventEmitter2`, and although these services might run\nin machines that are continents apart, any published updates will end up in a\n`Subscriber` as an event for us to consume.\n\nHere's how we might update `conversion-service.js` to listen to updates from the\narbitration service.\n\n```js\nsubscriber.on('rate updated', (update) =\u003e {\n    rates[update.currencies] = update.rate;\n});\n```\n\nLet's not forget to change the use of requester and responder in our conversion service and in our client to use segmentation key.\n\nconversion-service.js\n```js\nconst responder = new cote.Responder({ name: 'currency conversion responder', key: 'conversion' });\n```\n\nclient.js\n```js\nconst requester = new cote.Requester({ name: 'currency conversion requester', key: 'conversion' });\n```\n\nThat's it! From now on, this conversion service will synchronize with the\narbitration service and receive its updates. The new conversion requests after\nan update will be done over the new rate.\n\n\u003cdetails\u003e\n\u003csummary\u003e\n    Click to see the complete \u003ccode\u003econversion-service.js\u003c/code\u003e file.\n\u003c/summary\u003e\n\u003cp\u003e\n\n```js\nconst cote = require('cote');\n\nconst responder = new cote.Responder({ name: 'currency conversion responder', key: 'conversion' });\nconst subscriber = new cote.Subscriber({ name: 'arbitration subscriber' });\n\nconst rates = { usd_eur: 0.91, eur_usd: 1.10 };\n\nsubscriber.on('rate updated', (update) =\u003e {\n    rates[update.currencies] = update.rate;\n});\n\nresponder.on('convert', (req, cb) =\u003e {\n    const convertedRate = req.amount * rates[`${req.from}_${req.to}`];\n\n    cb(null, `${req.amount} ${req.from} =\u003e ${convertedRate} ${req.to}`);\n});\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n    Click to see the complete \u003ccode\u003eclient.js\u003c/code\u003e file.\n\u003c/summary\u003e\n\u003cp\u003e\n\n```js\nconst cote = require('cote');\n\nconst requester = new cote.Requester({ name: 'currency conversion requester', key:'conversion' });\n\nconst request = { type: 'convert', from: 'usd', to: 'eur', amount: 100 };\n\nrequester.send(request, (err, res) =\u003e {\n    console.log(res);\n});\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\nComponents Reference\n----\n\ncote hosts a number of components that together let you implement microservice\ncommunication. Below, you will find several examples on how to make use of each\ncomponent.\n\nBy default, every component can discover and interact with every other\ncomponent. This may not be desirable under certain conditions whereas security\nand network performance is of importance, so one can segregate or partition\ncomponent clusters with `key`s and `environment`s provided in configuration\nobjects.\n\nAlso, all components support `namespace`s. Given as a property of the\nconfiguration object to the constructor, components adhere and act on namespaces\nif provided, and ignore other messages. Namespaces are also handy in that they\nlet you wire a namespaced socket.io connection to the front-end. In other words,\nthe `namespace`s here also serve as socket.io namespaces.\n\n### Requester\n\nRequester queues requests until a Responder is available, and once so, it\ndelivers the request. Requests will be dispatched to Responders in a\nround-robin way.\n\nExample:\n\n```js\nconst cote = require('cote');\n\nconst randomRequester = new cote.Requester({\n    name: 'Random Requester',\n    // namespace: 'rnd',\n    // key: 'a certain key',\n    requests: ['randomRequest'],\n});\n\nsetInterval(() =\u003e {\n    const req = {\n        type: 'randomRequest',\n        val: Math.floor(Math.random() * 10),\n    };\n\n    randomRequester.send(req, (res) =\u003e {\n        console.log('request', req, 'answer', res);\n    });\n}, 5000);\n```\n\nRequesters also support `Promise`s, which gives you great flexibility when\nworking with promise-based libraries or when you want to chain multiple\n`Requester`s and `Responder`s.\n\nExample with promises:\n\n```js\nconst cote = require('cote');\nconst randomRequester = new cote.Requester({ name: 'Random Requester' });\n\nconst makeRequest = (req) =\u003e randomRequester.send(req);\n\nconst req = {\n    type: 'randomRequest',\n    val: Math.floor(Math.random() * 10),\n};\n\nmakeRequest(req)\n    .then(console.log)\n    .catch(console.log)\n    .then(process.exit);\n```\n\nExample with `async / await`:\n\n```js\nconst cote = require('cote');\nconst randomRequester = new cote.Requester({ name: 'Random Requester' });\n\nasync function makeRequest () {\n    const req = {\n        type: 'randomRequest',\n        val: Math.floor(Math.random() * 10),\n    };\n\n    const response = await randomRequester.send(req);\n    console.log(response);\n\n    process.exit();\n}\n\nmakeRequest();\n```\n\n#### Timeout\n\nA timeout could be configured for all Requesters as an environment variable\n`COTE_REQUEST_TIMEOUT`, or in advertisement options for specific Requester,\nor in a property called `__timeout` in first argument of `requester.send`\nmethod. Latter setting overrides former. Timeout is specified in milliseconds.\n\n**As environment variable for all requesters:**\n\n```sh\nCOTE_REQUEST_TIMEOUT=1000 node service.js\n```\n\n**In advertisement settings:**\n\n```js\nnew cote.Requester({ name: `Requester with timeout`, timeout: 1000 });\n```\n\n**In send data:**\n```js\nrequester.send({ type: 'find', __timeout: 2000 });\n```\n\n### Responder\n\nResponder is a component for responding to certain requests from a `Requester`.\nIt's a descendant of `EventEmitter2`, and requests are regular events, therefore\nmay be wildcarded or namespaced.\n\n`Responder` may be used to add new modules to existing web servers /\napplications without ever changing the main server code. Only a `Requester`\nwill be able to utilize a `Responder`.\n\nYou can use a `Responder` with a `Sockend` component to open a flexible API\nchannel for the front-end. This greatly reduces time-to-market by providing a\ndirect API for your front-end applications.\n\nExample:\n\n```js\nconst cote = require('cote');\n\n// Instantiate a new Responder component.\nconst randomResponder = new cote.Responder({\n    name: 'Random Responder',\n    // namespace: 'rnd',\n    // key: 'a certain key',\n    respondsTo: ['randomRequest'], // types of requests this responder\n                                  // can respond to.\n});\n\n// request handlers are like any event handler.\nrandomResponder.on('randomRequest', (req, cb) =\u003e {\n    const answer = Math.floor(Math.random() * 10);\n    console.log('request', req.val, 'answering with', answer);\n\n    cb(null, answer);\n});\n```\n\n`Responder`s also support `Promise`s, , which gives you great flexibility when\nworking with promise-based libraries or when you want to chain multiple\n`Requester`s and `Responder`s.\n\nExample with promises:\n\n`responder.js`\n```js\nconst cote = require('cote');\nconst UserModel = require('UserModel'); // a promise-based model API such as\n                                        // mongoose.\n\nconst userResponder = new cote.Responder({ name: 'User Responder' });\n\nuserResponder.on('find', (req) =\u003e UserModel.findOne(req.query));\n```\n\n`requester.js`\n```js\nconst cote = require('cote');\nconst userRequester = new cote.Requester({ name: 'User Requester' });\n\nuserRequester\n    .send({ type: 'find', query: { username: 'foo' } })\n    .then((user) =\u003e console.log(user))\n    .then(process.exit);\n```\n\nExample with `async / await`\n\n`responder.js`\n```js\nconst cote = require('cote');\nconst UserModel = require('UserModel'); // a promise-based model API such as\n                                        // mongoose.\n\nconst userResponder = new cote.Responder({ name: 'User Responder' });\n\nuserResponder.on('find', (req) =\u003e UserModel.findOne(req.query));\n```\n\n`requester.js`\n```js\nconst cote = require('cote');\nconst userRequester = new cote.Requester({ name: 'User Requester' });\n\nasync function makeRequest() {\n    const user = await userRequester.send({ type: 'find', query: { username: 'foo' });\n    console.log(user);\n\n    process.exit();\n}\n\nmakeRequest();\n\n```\n\n\n### Publisher\n\n`Publisher` is a component for publishing certain events with arbitrary data.\nIt may be used as a distributed `EventEmitter`. It may also be used in a\nscenario where some components need to be notified of updates, such as new\ntweets, etc. instead of polling for them. Only a `Subscriber` will get\nnotifications from a `Publisher`.\n\nThe messages `Publisher`s publish are volatile in that if there are no\n`Subscriber`s listening, they are lost.\n\n`Publisher`s may be used in conjunction with a `Sockend` component, in which\ncase the front-end clients will be notified of the events published. This is a\nvery cool real-time communication mechanism for your apps with no proprietary\ntechnology like Meteor.\n\nExample:\n\n```js\nconst cote = require('cote');\n\n// Instantiate a new Publisher component.\nconst randomPublisher = new cote.Publisher({\n    name: 'Random Publisher',\n    // namespace: 'rnd',\n    // key: 'a certain key',\n    broadcasts: ['randomUpdate'],\n});\n\n// Wait for the publisher to find an open port and listen on it.\nsetInterval(function() {\n    const val = {\n        val: Math.floor(Math.random() * 1000),\n    };\n\n    console.log('emitting', val);\n\n    // publish an event with arbitrary data at any time\n    randomPublisher.publish('randomUpdate', val);\n}, 3000);\n```\n\n### Subscriber\n\n`Subscriber` subscribes to events emitted from a `Publisher`.\n\nExample:\n\n```js\nconst cote = require('cote');\n\nconst randomSubscriber = new cote.Subscriber({\n    name: 'Random Subscriber',\n    // namespace: 'rnd',\n    // key: 'a certain key',\n    subscribesTo: ['randomUpdate'],\n});\n\nrandomSubscriber.on('randomUpdate', (req) =\u003e {\n    console.log('notified of ', req);\n});\n```\n\n### Sockend\n\n`Sockend` is the glue for carrying all the possibilities of cote to the next\nlevel with WebSockets over socket.io. `Sockend` makes `Responder`s and\n`Publisher`s available to the front-end and adhere to socket.io namespaces.\nIt's the magic and the lost link for microservices. Without any configuration,\nyou can expose APIs directly to the front-end.\n\nExample:\n\n`index.html`\n```html\n\u003cscript src=\"/socket.io/socket.io.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\nlet socket = io.connect();\nlet socketNamespaced = io.connect('/rnd');\n\nsocket.on('randomUpdate', function(data) {\n    console.log(data);\n});\n\nsetInterval(function() {\n    let req = {\n        val: Math.floor(Math.random() * 10),\n    };\n\n    let req2 = {\n        val: Math.floor(Math.random() * 10),\n    };\n\n    let req3 = {\n        val: Math.floor(Math.random() * 10),\n    };\n\n    let req4 = {\n        val: Math.floor(Math.random() * 10),\n    };\n\n    socket.emit('randomRequest', req, function(data) {\n        console.log('normal', req.val, data);\n    });\n\n    socketNamespaced.emit('randomRequest', req2, function(data) {\n        console.log('ns', req2.val, data);\n    });\n\n    socket.emit('promised request', req3, function(err, data) {\n        console.log('normal promised', req3.val, err, data);\n    });\n\n    socketNamespaced.emit('promised request', req4, function(err, data) {\n        console.log('ns promised', req4.val, err, data);\n    });\n}, 3000);\n\u003c/script\u003e\n```\n`sockend.js`\n\n```js\nconst cote = require('cote'),\n    app = require('http').createServer(handler),\n    io = require('socket.io').listen(app),\n    fs = require('fs');\n\nio.on('connection', (socket) =\u003e {\n    socket.join('room1');\n});\n\napp.listen(process.argv[2] || 5555);\n\nfunction handler(req, res) {\n    fs.readFile(__dirname + '/index.html', (err, data) =\u003e {\n        if (err) {\n            res.writeHead(500);\n            return res.end('Error loading index.html');\n        }\n\n        res.writeHead(200);\n        res.end(data);\n    });\n};\n\nconst sockend = new cote.Sockend(io, {\n    name: 'Sockend',\n    // key: 'a certain key'\n});\n```\n\nTo connect responder and sockend, you need to add `respondsTo:` parameter to your options.\n```js\nconst randomResponder = new Responder({\n    name: 'randomRep',\n    respondsTo: ['randomRequest', 'promised request'], // types of requests this responder\n    \t\t\t\t\t\t\t  // can respond to.\n});\n```\nTo connect publisher and sockend, you need to add `broadcasts:` parameter to your options\n\n```js\nlet randomPublisher = new Publisher({\n    name: 'randomPub',\n    broadcasts: ['update1', 'update2'],\n});\n```\n\nIf your socket is connected to a namespace, you need to add the same namespace to the components that you want to expose.\nEven though socket.io are prefixed with `/`, with sockend you need to omit `/`.\n\nsocket.io-client\n```js\nio.connect('/rnd'); // namespace in socket.io is declared as '/rnd'\n```\nsockend component\n```js\nconst randomResponder = new Responder({\n    name: 'randomRep',\n    namespace: 'rnd', // with sockend, we we omit the '/' and use just 'rnd'\n    respondsTo: ['randomRequest', 'promised request'], // types of requests this responder\n    \t\t\t\t\t\t\t  // can respond to.\n});\n```\n\nYou can check complete code for  `Responder`s and `Publisher`s in the `examples` folder. Fire them up\non default or 'rnd' namespace and watch them glow with magic on\n`http://localhost:5555`.\nIf you want to see more complete example of microservices with sockend integration, check out [the e-commerce case study](https://github.com/dashersw/cote-workshop)\n\n##### Socket.io Rooms\n`Sockend` supports socket.io rooms. All you need to do is add a `__rooms` or `__room` attribute to\nthe published message.\n\n```js\nconst randomPublisher = new cote.Publisher({\n    name: 'Random Publisher',\n    // namespace: 'rnd',\n    // key: 'a certain key',\n    broadcasts: ['randomUpdate'],\n});\n\nrandomPublisher.publish('randomUpdate', { val: 500, __rooms: ['room1', 'room2'] });\nrandomPublisher.publish('randomUpdate', { val: 500, __room: 'room1' });\n```\n\n### Monitor\n\nMonitor is the \"top\" of cote. It lists all the daemons it discovers regardless\nof namespace or key. Run `examples/monitor.js` and see all your active cote\ndaemons.\n\n### Monitoring Tool\n\ncote also has an infant of a monitoring tool that displays the cote ecosystem\nrunning in your environment in a nice graph. Run `examples/monitoring-tool.js`\nand navigate to `http://localhost:5555` in your browser to see your cote network\ngraph in action.\n\n## Advanced usage\n\nWhile cote is extremely simple to get started, the requirements for a system\nrunning in production may demand further tweaking and advanced settings. Here\nare some of the advanced features of cote, which can be adjusted on several\nlevels — as environment variables, as direct settings for the cote module when\nrequiring it, or as direct settings for each component.\n\nUntil now, we only saw instantiating cote components with a single argument. In\nfact, all cote components have two constructor parameters. The first is used as\nthe _advertisement_ configuration which controls the data being advertised for\nauto-discovery. The second parameter is the _discovery_ configuration and it\ncontrols the network-layer configuration and environments for components.\n\nWe'll see more details in the following section.\n\n### Environments\n\ncote works over IP broadcast or multicast. This means, for example, in an office\nnetwork where there are several developers running a project based on cote in\ntheir local machines, there _might_ be chaos. Components on a developer's\nmachine will discover other components on another developer's machine. This\nprobably is not a desired effect, and fortunately cote offers a way to combat\nthis.\n\nBy passing in an `environment` property to the configuration object of a\ncomponent, one can control the scope of auto-discovery for that particular\ncomponent. Components that are not in the same environment will ignore each\nother. This effectively creates network partitions.\n\n`environment`s can be set as an environment variable `COTE_ENV`.\n\nRunning a service with\n\n```sh\nCOTE_ENV=developer-1 node service.js\n```\n\nsets all the components within that service to use `developer-1` as an\n`environment`. This makes sure that however many modules `service.js` makes use\nof, they all will share the same `environment`, so this is the safest way to\nspecify `environment`s.\n\nThe other way to specify an `environment` is using the configuration argument\nto cote, given when requiring cote in the first place. Since Node.js modules are\nread and executed once from the disk, you need to make sure to pass in the configuration at least once, during the first require call. The subsequent\nrequires to cote will return the same module, which already has your\nconfiguration. If you have a bootstrap in your application that runs as the\nfirst thing in the application, it might be a good idea to put this config\nthere.\n\n#### Example\n\n```js\nconst cote = require('cote')({ environment: 'developer-2' });\n```\n\nNow the components in these services won't discover and communicate with each\nother.\n\nAnother place this comes handy is multiple environments running on a single\nmachine. Say you have a machine for your QA needs, where you host several\nenvironments for different tests, e.g. `integration` and `qa`. Again, components\nfrom different environments would mix up. Using a parametric `environment`, in\nthis case, solves this problem.\n\n### Keys\n\ncote has another mechanism to create partitions called `key`s.\nSince every component discovers and tries to communicate with every other\ncomponent on the horizon (this is called a \"mesh network\"), if different\nservices request and respond to different types of messages, you will\nexperience lost messages. In other words, if service A responds to messages X\nand Y, and service B responds to messages Z and T, you will lose half of the\nmessages, because messages Z and T will also end up at service A, but it won't\nknow how to handle them. The same is true for service B: messages X and Y\nwill end up at it, but service B won't know how to respond to them.\n\nKeys are useful in this scenario: requesters and responders around service A\nand messages X and Y should use one particular key, and requesters and\nresponders around service B and messages Z and T should use another key. In\nthis case, no messages will be lost, and the services will be segregated.\n\nIn our experience, the best way to segregate services is to follow the\nprinciples of domain-driven design. In this regard, for example, each domain\ncould have its own `key`. If you need more granular services, you should use\nmultiple keys inside the same domain. The principle is to ensure distinct keys\nfor a distinct set of messages. In other words, keys should represent a\ndistinct set of requests.\n\nPlease refer to [Creating the arbitration service]\n(https://github.com/dashersw/cote#creating-the-arbitration-service) for an\nexample of keys in action.\n\n`key`s are given as parameters to the configuration objects.\n\nWhen deciding whether to create a connection to another service, cote components\nmake use of `key`s and `environment`s together. Therefore, two components with\nexact same `environment`s with different `key`s wouldn't be able to communicate.\n\nThink of it as `${environment}_${key}`.\n\n#### Example\n\n```js\nconst cote = require('cote');\n\nconst purchaseRequester = new cote.Requester({\n    name: 'Purchase Requester',\n    key: 'purchase',\n});\n\nconst inventoryRequester = new cote.Requester({\n    name: 'Inventory Requester',\n    key: 'inventory',\n});\n```\n\nUnlike `environment`s, `key`s can't be used as an environment variable or part\nof cote's configuration, but rather, should be provided as part of the first\nargument to a component.\n\n### Namespaces\n\ncote includes a [Sockend](#sockend) component that provides a direct channel to\nthe frontend. This is extremely powerful and with power, comes great\nresponsibility. Exposing all the `Responder`s and `Publisher`s in the backend\nto your frontend application probably isn't a good idea. Therefore cote offers\n`namespace`s, which map conveniently to `socket.io` namespaces.\n\nTo help increase the security of backend services, components with\ndifferent `namespace`s won't recognize each other and try to communicate. This\neffectively segregates the front-facing components. In order to _allow_ a\ncomponent to talk to the frontend, you should use a `namespace` which shields\nthat service from the rest of the system. By incorporating multiple components\nin a single service, you can basically create proxies and let your front-facing\ncomponents interact with the rest of the system in a secure way.\n\n#### Example\n\n`front-facing-service.js`\n\n```js\nconst cote = require('cote');\n\nconst responder = new cote.Responder({\n    name: 'Conversion Sockend Responder',\n    namespace: 'conversion',\n});\n\nconst conversionRequester = new cote.Requester({\n    name: 'Conversion Requester',\n    key: 'conversion backend',\n});\n\nresponder.on('convert', (req, cb) =\u003e {\n    conversionRequester.send(req.type, req, cb); // proxy the request\n});\n```\n\n`backend-service.js`\n\n```js\nconst cote = require('cote');\n\nconst responder = new cote.Responder({\n    name: 'Conversion Responder',\n    key: 'conversion backend',\n});\n\nconst rates = { usd_eur: 0.91, eur_usd: 1.10 };\n\nresponder.on('convert', (req, cb) =\u003e {\n    cb(null, req.amount * rates[`${req.from}_${req.to}`]);\n});\n```\n\nJust like `key`s, `namespace`s can also only be utilized as part of the first\nargument to a component.\n\n### Multicast address\n\ncote works either with IP multicast or IP broadcast, defaulting to broadcast. If\nyou wish to use multicast instead, you can pass in a `multicast` property with\nthe configuration object to cote. This will make sure that the discovery will\nhappen only with the given configuration.\n\nIn fact, this is the best way to segregate services, not in the application\nlayer but at the network layer. This will create the minimal number of gossip\nmessages and the biggest gains in terms of performance. Therefore, using\ndifferent multicast addresses is better than using different environments or\nkeys.\n\nMuch like `environment`s, multicast addresses can be specified either as an\nenvironment variable or as part of the main configuration object to the cote\nrequire's. They can also be given as part of the _second_ configuration object.\n\n#### Example\n\nAs an environment variable:\n```sh\nCOTE_MULTICAST_ADDRESS=239.1.11.111 node service.js\n```\n\nAs part of cote's module configuration:\n\n```js\nconst cote = require('cote')({ multicast: '239.1.11.111' });\n```\n\nAs part of each component's discovery configuration:\n\n```js\nconst cote = require('cote');\n\nconst req = new cote.Requester({ name: 'req' }, { multicast: '239.1.11.111' });\n```\n\n### Broadcast address\nWhile multicast is good for segmentation, certain scenarios may require the\nconfiguration be done over IP broadcast. In that case, broadcast address\nconfiguration helps. Much like multicast configuration, cote supports 3\ndifferent ways of supplying broadcast configuration.\n\nMulticast configuration has precedence over broadcast. Therefore, when both\nconfigurations are applied, broadcast configuration will be ignored and\nmulticast configuration will take over.\n\nAlso, cote uses broadcast by default. Hence, if no configuration is provided,\nthe broadcast address will be set to `255.255.255.255`. If you want to use\nbroadcast, but have a different broadcast IP, you should configure it as shown\nbelow.\n\n#### Example\n\nAs an environment variable:\n```sh\nCOTE_BROADCAST_ADDRESS=255.255.255.255 node service.js\n```\n\nAs part of cote's module configuration:\n\n```js\nconst cote = require('cote')({ broadcast: '255.255.255.255' });\n```\n\nAs part of each component's discovery configuration:\n\n```js\nconst cote = require('cote');\n\nconst req = new cote.Requester({ name: 'req' }, { broadcast: '255.255.255.255' });\n```\n\n### Controlling cote with environment variables\n\nHere's a list of environment variables cote supports:\n\n| Variable name               | Description |\n| --------------------------: | :---------- |\n| `COTE_ENV`                  | See [Environments](#environments).\n| `COTE_MULTICAST_ADDRESS`    | See [Multicast address](#multicast-address).\n| `COTE_BROADCAST_ADDRESS`    | See [Broadcast address](#broadcast-address).\n| `COTE_USE_HOST_NAMES`       | In certain, extremely rare conditions, auto-discovery might fail due to components reporting wrong IP addresses. If you find out that is the case, you can command cote to use the reported host names instead.\n| `COTE_DISCOVERY_REDIS`      | See [Using centralized discovery tools](#using-centralized-discovery-tools).\n| `COTE_DISCOVERY_REDIS_URL`  | See [Using centralized discovery tools](#using-centralized-discovery-tools).\n| `COTE_DISCOVERY_REDIS_HOST` | See [Using centralized discovery tools](#using-centralized-discovery-tools).\n| `DISCOVERY_HOSTNAME`        | See [Using centralized discovery tools](#using-centralized-discovery-tools).\n| `COTE_REQUEST_TIMEOUT`      | See [Requester Timeout](#timeout).\n| `COTE_LOG`                  | Boolean. Whether to display hello and status logs for other discovered services. Has precedence over `COTE_STATUS_LOGS_ENABLED` and `COTE_HELLO_LOGS_ENABLED`.\n| `COTE_HELLO_LOGS_ENABLED`   | Boolean. Whether to display hello logs from other discovered services.\n| `COTE_STATUS_LOGS_ENABLED`  | Boolean. Whether to display status logs from other discovered services. Has precedence over `COTE_HELLO_LOGS_ENABLED`.\n| `COTE_LOG_UNKNOWN_EVENTS`   | Boolean. Whether to log a message when a responder or subscriber receives an event that it has no listeners for. Defaults to true.\n| `COTE_CHECK_INTERVAL`       | Integer. The interval for checking if a discovered service has sent a heartbeat since the last check.\n| `COTE_HELLO_INTERVAL`       | Integer. The interval for sending a heartbeat hello signal. Should be less than `COTE_CHECK_INTERVAL`.\n| `COTE_NODE_TIMEOUT`         | Integer. The timeout duration that determines if a service is unreachable and thus removed. Should be greater than `COTE_CHECK_INTERVAL`.\n| `COTE_IGNORE_PROCESS`       | Boolean. Whether the services defined in this process should ignore other services from this process. This might be useful in a high-availability setup where one wants to enforce collaboration of services over the network, instead of local services within each process.\n\n## Deploying with Docker Cloud (deprecated)\n\ncote plays extremely well with Docker Cloud. Even if your cloud provider doesn't\nsupport IP broadcast or multicast, you can still have the same functionality\nwith Docker Cloud's Weave overlay networks.\n\nJust deploy your cote applications just like any other Node.js application and\neven when your containers run in different machines on different continents, as\nlong as they share an overlay network — which Docker Cloud assigns by default\nanyway — everything will work as expected.\n\nMake sure to check out\n[the e-commerce case study](https://github.com/dashersw/cote-workshop) that\nimplements a complete e-commerce application with microservices using\n[cote](https://github.com/dashersw/cote). It features example Dockerfiles and\ndocker-compose configurations in addition to Docker Cloud configurations.\n\nIt also has a Docker Swarm configuration to get you started on using cote with\nDocker Swarm, in any cloud environment.\n\n## Using centralized discovery tools\n\ncote is built to be zero-configuration, and relies on IP broadcast/multicast\nto work. cloud providers don't support this functionality (and they won't)\nout of the box. In these cases, one can use the Weave network overlay\nintegration. However, this may not be suitable for everyone, due to\nvarying reasons.\n\n### Welcome redis\n\nIn these cases, in order to let cote work, we developed a plugin mechanism to\naccommodate different solutions that can serve as the automated service\ndiscovery tool. Currently, redis is supported out of the box, and cote\nmakes use of the [node_redis](https://github.com/NodeRedis/node_redis)\nlibrary, in case you want to use redis as the central discovery tool. If you\nneed to use anything other than redis, please open\n[a new issue](https://github.com/dashersw/cote/issues/new) and we may be\nable to help.\n\nYou should also set `DISCOVERY_HOSTNAME` to the **IP address**\nof the container/instance since it defaults to machine's hostname which in\nmost cloud/docker setups is not routable.\n\n### Configuring redis\n\ncote aims to be as zero-conf as possible. Therefore, the discovery backend\nshould be invisible to the developer. Since IP broadcast/multicast\nfunctionality is environment-specific, it makes sense to configure a\ncentralized solution via environment variables as well. This way, the\ncontainer deployment configurations such as Docker Swarm stack definitions\ncan make use of the additional redis backend functionality, while developers\ncan still use IP broadcast/multicast locally, with the same source code.\n\nThat's why cote uses environment variables that start with\n`COTE_DISCOVERY_REDIS`. cote transforms any environment variable that\nstarts with `COTE_DISCOVERY_REDIS` to proper configuration for the\n[node_redis](https://github.com/NodeRedis/node_redis) library. For example,\n`COTE_DISCOVERY_REDIS_URL=redis` becomes `{ url: 'redis' }` and\n`COTE_DISCOVERY_REDIS_HOST=redis COTE_DISCOVERY_REDIS_PORT=6379` becomes\n`{ host: 'redis', port: '6379' }`.\n\n| Variable name               | Description |\n| --------------------------: | :---------- |\n| `COTE_DISCOVERY_REDIS`        | If you are running redis on localhost, setting this variable to true will use the locally available redis at port 6379. If you need any other redis URL or host, you don't need to use this variable.\n| `COTE_DISCOVERY_REDIS_URL`    | Sets the redis connection URL. Has to start with either `redis://` or `//`. Enables the redis plugin.\n| `COTE_DISCOVERY_REDIS_HOST`   | Sets the redis connection host name. Enables the redis plugin.\n| `COTE_DISCOVERY_REDIS_PORT`   | Sets the redis connection port. Enables the redis plugin.\n| `DISCOVERY_HOSTNAME`          | This defaults to your machine's `hostname`. If this is not routable you need to set this to the routable IP address of this instance.\n\ncote also supports other connection options supported by\n[node_redis](https://github.com/NodeRedis/node_redis) in the same manner.\n\n#### Example\n\nAs an environment variable:\n```sh\nCOTE_DISCOVERY_REDIS_HOST=redis DISCOVERY_HOSTNAME=127.0.0.1 node service.js\n```\n\nAs part of cote's module configuration:\n\n```js\nconst cote = require('cote')({ redis: { host: 'redis' } });\n```\n\nAs part of each component's discovery configuration:\n\n```js\nconst cote = require('cote');\n\nconst req = new cote.Requester({ name: 'req' }, { redis: { host: 'redis' } });\n```\n\n# FAQ\n\n## Is cote production-ready?\n\ncote is battle-tested, solid and has been running in production across thousands\nof services since its inception in 2013. cote follows\n[Semantic Versioning](http://semver.org) and is production-ready.\n\n## Usage with PM2\n\nMake sure you don't run any of your services in cluster mode. It messes up the\nservice discovery since it tries to load balance the UDP ports used internally\nfor this purpose.\n\nTo use Cote properly within PM2 cluster mode, server instances should only be instantiated once.\nTo do so, utilize `process.env.pm_id`, which will return a value between 0 and the total number of instances(N).  For example, if 10 instances of your app are running in cluster mode `pm2 start app.js -i 10`, `process.env.pm_id` will return a value of (0-9) inclusively.\n\n```js\n// In thise case, we choose only the third app instance (2 because it is zero based) to instantiate a \"SERVER\"\n// any number from 0 through 9 can be used, instead of 2\nif (process.env.pm_id == 2) {\n   const cote = require('cote');\n   const timeService = new cote.Responder({\n      name: 'Time Service'\n   });\n   timeService.on('time', (req, cb) =\u003e {\n     cb(new Date());\n   });\n}\n```\n\n## Running with cloud providers (AWS, DigitalOcean, etc)\n\nMost cloud providers block IP broadcast and multicast, therefore you can't run\ncote in a multi-host environment without special software for an overlay\nnetwork. For this purpose, Docker is the best tool. Deploy your application in\nDocker containers and you can take advantage of its overlay networks. Users of\nDocker Swarm can make use of the [Weave Net plugin](https://www.weave.works/docs/net/latest/plugin-v2/).\nWeave also has [an addon](https://www.weave.works/docs/net/latest/kube-addon/) for\nenabling multicast/broadcast for Kubernetes.\n\nIf you find the solutions with Docker Swarm and Kubernetes to be hard to get\nstarted with, you can use redis as a centralized discovery tool. Check out\n[Using centralized discovery tools](#using-centralized-discovery-tools) to\nsee how you can set up redis to work with cote.\n\n# Contribution\n\ncote is under constant development, and has several important issues still open.\nWe would therefore heavily appreciate if you headed to the\n[project](https://github.com/dashersw/cote/projects/1) to see where we are in\nthe development, picked an issue of your taste and gave us a hand.\n\nIf you would like to see a feature implemented or want to contribute a new\nfeature, you are welcome to open an issue to discuss it and we will be more than\nhappy to help.\n\nIf you choose to make a contribution, please fork this repository, work on a\nfeature and submit a pull request. cote is the next level of microservices —\nbe part of the revolution.\n\nMIT License\n----\n\nCopyright (c) 2013 Armagan Amcalar\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fdashersw%2Fcote.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fdashersw%2Fcote?ref=badge_large)\n","funding_links":[],"categories":["JavaScript","nodejs","Service Toolkits"],"sub_categories":["Node.js"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdashersw%2Fcote","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdashersw%2Fcote","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdashersw%2Fcote/lists"}