{"_id":"@codedependant/kubernetes-leader-election","_rev":"3-8ccb89d2608764a10c2718b3f7a04684","name":"@codedependant/kubernetes-leader-election","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"@codedependant/kubernetes-leader-election","version":"1.0.0","keywords":["kubernetes","leader","election","lease"],"author":{"name":"Eric Satterwhite","email":"esatterwhite@wi.rr.com"},"license":"SEE LICENSE IN LICENSE","_id":"@codedependant/kubernetes-leader-election@1.0.0","maintainers":[{"name":"codedependant","email":"eric@codedependant.net"}],"homepage":"https://github.com/esatterwhite/kubernetes-leader-election","bugs":{"url":"https://github.com/esatterwhite/kubernetes-leader-election/issues"},"tap":{"files":["test/unit","test/integration"],"serial":["test/unit/roles","test/integration/routes/v3/auth/role"],"browser":false,"output-file":".tap-out","coverage-report":["text","text-summary"],"allow-incomplete-coverage":true},"dist":{"shasum":"5102d91beec202fb1d5593b7f31c7855ecc9bdc6","tarball":"https://registry.npmjs.org/@codedependant/kubernetes-leader-election/-/kubernetes-leader-election-1.0.0.tgz","fileCount":8,"integrity":"sha512-cet5LTiruTE54QmNJuFveeQ3aBZLeP6qBKHsiecV/Lbz8F7UPWuDf+CAGWBQGUW3F+F0V8OQs7gINGHqhri3Xg==","signatures":[{"sig":"MEUCIQCpIoodFUOkABciwzhwVPy4wYdFDc0k2aaz7W+lwjmh2wIgIlbB/76QMB37oOcMI1lFAMWGlqDJ4t/nJZxCupVOOZc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58788},"main":"index.js","gitHead":"e2e2e8dc9639944ca4f5f502b8070f2f18d90587","scripts":{"c8":"c8","tap":"tap","lint":"eslint ./","stop":"tilt down -f tilt/Tiltfile","test":"scripts/test-ci.sh","local":"KUBERNETES_SERVICE_HOST=$(./scripts/get-cluster-host) KUBERNETES_SERVICE_PORT=$(./scripts/get-cluster-port)","start":"tilt up -f tilt/Tiltfile","kind:up":"scripts/kind-up","posttap":"npm run c8:report","pretest":"npm run lint","release":"semantic-release","lint:fix":"npm run lint -- --fix","c8:report":"c8 report","kind:down":"scripts/kind-down","c8:coverage":"c8 check-coverage"},"_npmUser":{"name":"codedependant","email":"eric@codedependant.net"},"repository":{"url":"git+https://github.com/esatterwhite/kubernetes-leader-election.git","type":"git"},"_npmVersion":"10.9.2","description":"Leader election for kubernetes using leases","directories":{},"_nodeVersion":"22.14.0","dependencies":{"abstract-logging":"^2.0.1","@kubernetes/client-node":"^1.3.0"},"eslintConfig":{"root":true,"extends":"logdna","parserOptions":{"ecmaVersion":2022},"ignorePatterns":["node_modules/","coverage/"]},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"c8":"^10.1.3","tap":"^21.1.0","pino":"^9.7.0","yaml":"^2.8.0","eslint":"^8.57.1","tap-xunit":"^2.4.1","tap-parser":"^18.0.0","pino-pretty":"^13.0.0","semantic-release":"^17.4.7","@logdna/setup-chain":"^1.3.2","eslint-config-logdna":"^7.0.3","@semantic-release/git":"^9.0.1","@semantic-release/changelog":"^5.0.1","@codedependant/release-config-npm":"^1.0.4"},"_npmOperationalInternal":{"tmp":"tmp/kubernetes-leader-election_1.0.0_1754600443508_0.8810098123259504","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@codedependant/kubernetes-leader-election","version":"1.0.1","keywords":["kubernetes","leader","election","lease"],"author":{"name":"Eric Satterwhite","email":"esatterwhite@wi.rr.com"},"license":"SEE LICENSE IN LICENSE","_id":"@codedependant/kubernetes-leader-election@1.0.1","maintainers":[{"name":"codedependant","email":"eric@codedependant.net"}],"homepage":"https://github.com/esatterwhite/kubernetes-leader-election","bugs":{"url":"https://github.com/esatterwhite/kubernetes-leader-election/issues"},"tap":{"files":["test/unit","test/integration"],"serial":["test/unit/roles","test/integration/routes/v3/auth/role"],"browser":false,"output-file":".tap-out","coverage-report":["text","text-summary"],"allow-incomplete-coverage":true},"dist":{"shasum":"39706e5ca6e29938e81c1d621c7b07d3723083f5","tarball":"https://registry.npmjs.org/@codedependant/kubernetes-leader-election/-/kubernetes-leader-election-1.0.1.tgz","fileCount":7,"integrity":"sha512-ZhEBIMvNSNlnI7k2iTrd95eZNVj+qZ90qF8YZoKQ+gPgCmwClSjRdCyUMuiMUxMhZNg3zG6g+okf//3yF4oSag==","signatures":[{"sig":"MEUCIQCdm8LbZmTaBFDQEtc0p91J/+qiiSmZbdQo7GK6ayWrSgIgDwWIss31dnsCUwQrc7RCNrOyRpk+gjtFtwnbZJVcf+c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58034},"main":"index.js","gitHead":"4616db505a95ae21d5d15a4224c5941a90edcf56","scripts":{"c8":"c8","tap":"tap","lint":"eslint ./","stop":"tilt down -f tilt/Tiltfile","test":"scripts/test-ci.sh","local":"KUBERNETES_SERVICE_HOST=$(./scripts/get-cluster-host) KUBERNETES_SERVICE_PORT=$(./scripts/get-cluster-port)","start":"tilt up -f tilt/Tiltfile","kind:up":"scripts/kind-up","posttap":"npm run c8:report","pretest":"npm run lint","release":"semantic-release","lint:fix":"npm run lint -- --fix","c8:report":"c8 report","kind:down":"scripts/kind-down","c8:coverage":"c8 check-coverage"},"_npmUser":{"name":"codedependant","email":"eric@codedependant.net"},"repository":{"url":"git+https://github.com/esatterwhite/kubernetes-leader-election.git","type":"git"},"_npmVersion":"10.8.2","description":"Leader election for kubernetes using leases","directories":{},"_nodeVersion":"18.20.8","dependencies":{"abstract-logging":"^2.0.1","@kubernetes/client-node":"^1.3.0"},"eslintConfig":{"root":true,"extends":"logdna","parserOptions":{"ecmaVersion":2022},"ignorePatterns":["node_modules/","coverage/"]},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"c8":"^10.1.3","tap":"^21.1.0","pino":"^9.7.0","yaml":"^2.8.0","eslint":"^8.57.1","tap-xunit":"^2.4.1","tap-parser":"^18.0.0","pino-pretty":"^13.0.0","semantic-release":"^17.4.7","@logdna/setup-chain":"^1.3.2","eslint-config-logdna":"^7.0.3","@semantic-release/git":"^9.0.1","@semantic-release/changelog":"^5.0.1","@codedependant/release-config-npm":"^1.0.4"},"_npmOperationalInternal":{"tmp":"tmp/kubernetes-leader-election_1.0.1_1754618949048_0.33271509054329895","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@codedependant/kubernetes-leader-election","description":"Leader election for kubernetes using leases","version":"1.0.2","main":"index.js","scripts":{"c8":"c8","c8:coverage":"c8 check-coverage","c8:report":"c8 report","kind:up":"scripts/kind-up","kind:down":"scripts/kind-down","lint":"eslint ./","lint:fix":"npm run lint -- --fix","local":"KUBERNETES_SERVICE_HOST=$(./scripts/get-cluster-host) KUBERNETES_SERVICE_PORT=$(./scripts/get-cluster-port)","pretest":"npm run lint","release":"semantic-release","start":"tilt up -f tilt/Tiltfile","stop":"tilt down -f tilt/Tiltfile","tap":"tap","posttap":"npm run c8:report","test":"scripts/test-ci.sh"},"author":{"name":"Eric Satterwhite","email":"esatterwhite@wi.rr.com"},"repository":{"type":"git","url":"git+https://github.com/esatterwhite/kubernetes-leader-election.git"},"homepage":"https://github.com/esatterwhite/kubernetes-leader-election","bugs":{"url":"https://github.com/esatterwhite/kubernetes-leader-election/issues"},"license":"SEE LICENSE IN LICENSE","publishConfig":{"access":"public"},"keywords":["kubernetes","leader","election","lease"],"eslintConfig":{"root":true,"ignorePatterns":["node_modules/","coverage/"],"extends":"logdna","parserOptions":{"ecmaVersion":2022}},"tap":{"browser":false,"allow-incomplete-coverage":true,"coverage-report":["text","text-summary"],"output-file":".tap-out","serial":["test/unit/roles","test/integration/routes/v3/auth/role"],"files":["test/unit","test/integration"]},"devDependencies":{"@codedependant/release-config-core":"^1.1.1","@logdna/setup-chain":"^1.3.2","@semantic-release/changelog":"^6.0.3","c8":"^10.1.3","eslint":"^8.57.1","eslint-config-logdna":"^7.0.3","pino":"^9.7.0","pino-pretty":"^13.0.0","semantic-release":"^25.0.9","tap":"^21.1.0","tap-parser":"^18.0.0","tap-xunit":"^2.4.1","yaml":"^2.8.0"},"dependencies":{"@kubernetes/client-node":"^1.3.0","abstract-logging":"^2.0.1"},"gitHead":"61d2f8f9daba117d2e636ddf2f544dd3ffe053cf","_id":"@codedependant/kubernetes-leader-election@1.0.2","_nodeVersion":"24.19.0","_npmVersion":"11.19.1","dist":{"integrity":"sha512-p7WX8+tgTVkm2oQlLXVqycNuVoTmZ7kzUCvV4BgvtGXa4mAQxy306BTvEFXdh8MvvwDXpZhhc5MQzhXI46fwMQ==","shasum":"5a0650f8545f735b3bc324f1d79ae799924d4cf6","tarball":"https://registry.npmjs.org/@codedependant/kubernetes-leader-election/-/kubernetes-leader-election-1.0.2.tgz","fileCount":7,"unpackedSize":57997,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@codedependant%2fkubernetes-leader-election@1.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCpxwEm7WsWMVdxnx6A0BTyOPDzHaYRUy1YP+x/ExSllgIgPo+/KIW3O7mkenI2S2TbBNfqzvmdlS6Uu2ieRK67bMg="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cf483b63-2746-4570-aa59-8d35d4ec8e0d"}},"directories":{},"maintainers":[{"name":"codedependant","email":"eric@codedependant.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/kubernetes-leader-election_1.0.2_1787797117966_0.46534733486072377"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-07T21:00:43.195Z","modified":"2026-08-27T02:18:38.421Z","1.0.0":"2025-08-07T21:00:43.848Z","1.0.1":"2025-08-08T02:09:09.219Z","1.0.2":"2026-08-27T02:18:38.105Z"},"bugs":{"url":"https://github.com/esatterwhite/kubernetes-leader-election/issues"},"author":{"name":"Eric Satterwhite","email":"esatterwhite@wi.rr.com"},"license":"SEE LICENSE IN LICENSE","homepage":"https://github.com/esatterwhite/kubernetes-leader-election","keywords":["kubernetes","leader","election","lease"],"repository":{"type":"git","url":"git+https://github.com/esatterwhite/kubernetes-leader-election.git"},"description":"Leader election for kubernetes using leases","maintainers":[{"name":"codedependant","email":"eric@codedependant.net"}],"readme":"## Kubernetes Leader Election\n\nLeader election for kubernetes using leases\n\n### Installation\n\n```bash\nnpm install @codedependant/kubernetes-leader-election -- save\n```\n\n\n<!-- vim-markdown-toc GFM -->\n\n* [Exports](#exports)\n    * [Events](#events)\n    * [Elector](#elector)\n* [Classes](#classes)\n    * [Elector(`options`)](#electoroptions)\n        * [Properties](#properties)\n        * [Methods](#methods)\n            * [`start`(): Promise&lt;void&gt;](#start-promiseltvoidgt)\n            * [`stop`(): Promise&lt;void&gt;](#stop-promiseltvoidgt)\n* [Usage](#usage)\n    * [Kubernetes RBAC](#kubernetes-rbac)\n        * [Service Account](#service-account)\n        * [Role](#role)\n        * [RoleBinding](#rolebinding)\n        * [Example Deployment](#example-deployment)\n* [Authors](#authors)\n\n<!-- vim-markdown-toc -->\n\n## Exports\n\n### Events\n* ([Object][]) - Named events that are emitted from elector instances\n    * ([String][]) LEADERSHIP_ACQUIRED Event emitted when an elector claims ownership of a lease\n    * ([String][]) LEADERSHIP_LOST - Event emitted when an elector recognizes a different elector has claimed ownership\n    * ([String][]) LEASE_RENEWED - Event emitted when the currently leader renews its lease resource\n\n### [Elector](#electoroptions)\n* ([Class][]) Elector - Elector instances configured with the same lease name will form a coordination group in which\n              one, and only one elector instance can be considered the leader\n\n## Classes\n\n**Extends**: [EventEmitter][]\n\n### Elector(`options`)\n\n**Arguments**\n\n* (optional) `options` ([Object][]): Configuration options for the elector\n    * (optional) `auto_close` [Boolean][]: If true, the elector will try to stop itself when the `SIGINT` and `SIGTERM` signals are sent to the process\n        * default: **true**\n    * (optional) `identity` [String][]: A **unique** name for the elector used to claim leadership. THe name of the kubernetes pod is generally safe.\n        * default: **elector-{{hostname}}-{{process-id}}**\n    * (optional) `lease_name` [String][]: The name of the kubernetes lease the electors will manage.\n        * default: `nodejs-leader-election`\n    * (optional) `log` [Object][]: A logger instance that implements the [abstract-logging][] interface. [pino][] is recommended.\n    * (optional) `namespace` [String][]: The namespace the elector should be constrained to\n        * default: **default**\n    * (optional) `renew_interval_ms` [Number][]: The frequency at which the leader will attempt to renew its lease\n        * default: **10000**\n    * (optional) `lease_duration_sec` [Number][]: The amount of time assigned to the active lease. After which it is considered expired and the election process will start again\n        * default: **20** (Calculated as (2 * renew_interval_ms) / 1000)\n    * (optional) `wait_for_leadership` [Boolean][]: If `true`, when the start() method is called, the elector will wait for a leader to be elected.\n        * default: **false**\n\n#### Properties\n\n* current_leader [Boolean][] - Indicates if the elector instance is currently the leader\n* lease_name [String][] - The name of the kubernetes lease resources that is being managed\n* identity [String][] - The unique name of the elector instance\n* namespace [String][] - the kubernetes namespaces the elector is currently bound to\n\n#### Methods\n\n##### `start`(): [Promise][]&lt;void&gt;\n##### `stop`(): [Promise][]&lt;void&gt;\n\n## Usage\n\nThe elector instance depends entirely on the kubernetes API. As such, if it cannot determine\nthat it is running in a kubernetes environment, It will not attempt to interact with the\napi and it will assume leadership. Generally useful for development when not running in kubernetes.\nWhen created, the elector will check for the environment variable `KUBERNETES_SERVICE_HOST` to\nmake this determination\n\n```javascript\n\nconst {Elector, EVENTS} = require('@codedependant/kubernetes-leader-election')\n\nconst elector = new Elector({\n  lease_name: 'my-application-lease'\n, auto_close: false\n, identity: process.env.POD_NAME || `my-application-${process.pid}`\n})\n\nelector.on(EVENTS.LEADERSHIP_ACQUIRED, (evt) => {\n  // handle becoming the leader\n  importantFunction(evt)\n})\n\nelector.on(EVENTS.LEADERSHIP_LOST, () => {\n  // Handle not being the leader\n  importantFunction(evt)\n})\n\nprocess.on('SIGINT', onSignal)\nprocess.on('SIGTERM', onSignal)\n\nasync importantFunction(...args) {\n  if (!elector.current_leader) {\n    console.log(`I'm not the leader. Nothing to do`)\n    return\n  }\n  // Do something important that only the leader can do\n  console.log('Important work has been done')\n}\nfunction onSignal(signal) {\n  elector.log.info('received signal %s', signal)\n  elector.stop()\n}\n\nelector.start()\n```\n\n### Kubernetes RBAC\n\nTo allow your application to manage leases, set up the appropriate RBAC configuration in Kubernetes.\nThis involves creating a ServiceAccount, Role, and a RoleBinding or ClusterRoleBinding\nto grant the necessary permissions.\n\nBelow is an example of the minimal setup required\n\n#### Service Account\n\n```yaml\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: kubernetes-election\n  namespace: default\n```\n\n#### Role\n\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: lease-manager\n  namespace: default\nrules:\n  - apiGroups:\n      - coordination.k8s.io\n    resources:\n      - leases\n    verbs:\n      - get\n      - list\n      - watch\n      - create\n      - update\n      - patch\n      - delete\n```\n\n#### RoleBinding\n\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: lease-manager-binding\n  namespace: default\nsubjects:\n- kind: ServiceAccount\n  name: kubernetes-election\n  namespace: default\nroleRef:\n  kind: Role\n  name: lease-manager\n  apiGroup: rbac.authorization.k8s.io\n```\n\n#### Example Deployment\n\nOnce this is in place, any deployment or pod that makes use of this package should leverage\nthe previously defined service account. It is highly recommended to make use of the pod name\nas the elector instance's identity\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: elector\n  labels:\n    app: elector\nspec:\n  selector:\n    matchLabels:\n      app: elector\n  template:\n    metadata:\n      labels:\n        app: elector\n    spec:\n      serviceAccountName: kubernetes-election\n      containers:\n        - name: application\n          image: your-node-application:latest\n          command:\n            - node\n          args:\n            - 'index.js'\n          env:\n            - name: POD_NAME\n              valueFrom:\n                fieldRef:\n                  apiVersion: v1\n                  fieldPath: metadata.name\n```\n\n## Authors\n\n* [**Eric Satterwhite**](mailto:esatterwhite@wi.rr.com) &lt;esatterwhite@wi.rr.com&gt;\n\n[String]: https://mdn.io/string\n[Object]: https://mdn.io/object\n[Class]: https://mdn.io/classes\n[Promise]: https://mdn.io/promise\n[Boolean]: https://mdn.io/boolean\n[Number]: https://mdn.io/number\n[abstract-logging]: https://www.npmjs.com/package/abstract-logging\n[pino]: https://www.npmjs.com/package/pino\n[EventEmitter]: https://nodejs.org/api/events.html#class-eventemitter\n","readmeFilename":"README.md"}