{"_id":"@dvsantd/polaris","name":"@dvsantd/polaris","dist-tags":{"latest":"0.3.30"},"versions":{"0.3.30":{"name":"@dvsantd/polaris","version":"0.3.30","description":"Polaris SDK","author":{"name":"superzheng","email":"superzheng@dvsantd.com"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"http://git.code.oa.com/polaris/polaris-nodejs.git"},"funding":"wxwork://message?username=superzheng","bugs":{"url":"https://git.woa.com/polaris/polaris-nodejs/issues"},"homepage":"https://git.woa.com/polaris/polaris-nodejs","keywords":["polaris"],"scripts":{"build":"npm run lint && npm run clean && npm run build:src && npm run build:scripts && npm run pb:ts && npm run pb:dist:base && npm run pb:dist:grpc","build:src":"tsc -p tsconfig.json","build:scripts":"tsc -p tsconfig.scripts.json","coverage":"cross-env NODE_ENV=test nyc ava","clean":"shx rm -rf .nyc-output coverage dist","lint":"eslint --max-warnings=0 \"@(src|test|tools)/**/*.@(js|ts)\"","check":"npm run build","test":"cross-env NODE_ENV=test ava","pb:ts":"ts-node ./tools/pb2ts.ts src/plugins/naming/polaris-server/discover-pb src/plugins/naming/polaris-server/monitor-pb src/plugins/naming/polaris-server/ratelimit-pb","pb:dist:base":"shx cp -r src/plugins/naming/polaris-server/discover-pb src/plugins/naming/polaris-server/monitor-pb src/plugins/naming/polaris-server/ratelimit-pb dist/plugins/naming/polaris-server/","pb:dist:grpc":"shx cp -r src/plugins/naming/polaris-server/connector/grpc/pb dist/plugins/naming/polaris-server/connector/grpc/pb","lines":"bash -c \"find . -name \\*.ts | grep -v -E tools\\|test\\|node_modules\\|.d.ts | xargs cat | wc -l\"","postinstall":"node -e \"try{require('./dist/scripts/postinstall')}catch(e){}\""},"devDependencies":{"@commitlint/cli":"^12.1.1","@commitlint/config-conventional":"^12.1.1","@dvsantd/eslint-config-halo":"^8.4.0","@types/debug":"^4.1.5","@types/node":"^14.14.37","@types/semver":"^7.3.3","@types/uuid":"^8.3.0","@types/sinon":"^9.0.11","ava":"^3.15.0","cross-env":"^7.0.3","eslint":"^7.24.0","husky":"^6.0.0","nyc":"^15.1.0","shx":"^0.3.2","sinon":"^9.2.4","tmp-promise":"^3.0.2","ts-node":"^9.1.1","typescript":"^4.2.4"},"husky":{"hooks":{"commit-msg":"commitlint -e .git/COMMIT_EDITMSG","pre-push":"npm run check"}},"nyc":{"extension":[".ts"],"include":["src/**/*.ts"],"exclude":["**/*.d.ts"],"reporter":["lcov","text","text-summary"]},"ava":{"extensions":["ts"],"require":["ts-node/register"],"files":["test/**/*.test.ts"],"ignoredByWatcher":["!src/**/*.ts"]},"commitlint":{"extends":["@commitlint/config-conventional"],"rules":{"subject-case":[0]}},"dependencies":{"@grpc/grpc-js":"^1.2.12","@grpc/proto-loader":"^0.6.0","@types/hashring":"^3.2.1","axios":"^0.21.1","debug":"^4.3.1","hashring":"^3.2.0","protobufjs":"^6.10.2","semver":"^7.3.5","uuid":"^8.3.2"},"_id":"@dvsantd/polaris@0.3.30","_nodeVersion":"18.20.0","_npmVersion":"10.5.0","dist":{"integrity":"sha512-Jid856kbodn8hD1DKTRg+Uo45fsETikZM5A0c42SCl0h4hAb8nY4bGTYuD0xee0bA3eLE+m0K54FV3BECqWY7Q==","shasum":"1546a6135e2e2ec0c8ed2c79d686d20c5084ab34","tarball":"https://registry.npmjs.org/@dvsantd/polaris/-/polaris-0.3.30.tgz","fileCount":193,"unpackedSize":771612,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEw6PP/BFngi58SZQJJgqzZoAXKGvsyl1YJ8ckv13OCQAiBryAlcXWnKAfUmzzf9GaGBywvC2qaXIdZTqkc9XGpFbA=="}]},"_npmUser":{"name":"dvsantd","email":"harrydolly1226@hotmail.com"},"directories":{},"maintainers":[{"name":"dvsantd","email":"harrydolly1226@hotmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/polaris_0.3.30_1723112745934_0.17264141507766206"},"_hasShrinkwrap":false}},"time":{"created":"2024-08-08T10:25:45.846Z","0.3.30":"2024-08-08T10:25:46.389Z","modified":"2024-08-08T10:25:46.650Z"},"maintainers":[{"name":"dvsantd","email":"harrydolly1226@hotmail.com"}],"description":"Polaris SDK","homepage":"https://git.woa.com/polaris/polaris-nodejs","keywords":["polaris"],"repository":{"type":"git","url":"http://git.code.oa.com/polaris/polaris-nodejs.git"},"author":{"name":"superzheng","email":"superzheng@dvsantd.com"},"bugs":{"url":"https://git.woa.com/polaris/polaris-nodejs/issues"},"license":"MIT","readme":"# Polaris SDK\r\n\r\n[![build status](http://badge.orange-ci.woa.com/polaris/polaris-nodejs.svg)](http://orange-ci.oa.com/build/log/latest?slug=polaris/polaris-nodejs) [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)\r\n\r\nPolaris（北极星）是名字服务协同团队合力研发的服务治理组件，具备服务注册、健康检查、服务发现、服务路由、负载均衡、故障节点熔断、动态权重调整与服务限流等功能。\r\n\r\nPolaris Node.js SDK 采用微内核(Microkernel) + 插件(Plugins) 设计，可支持替换 11 种不同类型插件。\r\n\r\n项目（包括依赖部分） 100% 由 TypeScript(JavaScript) 编写，不含任何 C/C++ 代码。\r\n\r\n## 目录\r\n\r\n- [安装](#安装)\r\n- [例子](#例子)\r\n- [使用](#使用)\r\n  - [运行模式](#运行模式)\r\n  - [公共类型](#公共类型)\r\n    - [实例](#实例)\r\n    - [位置](#位置)\r\n    - [元数据](#元数据)\r\n  - [Consumer API](#consumer-api)\r\n  - [Provider API](#provider-api)\r\n  - [Limiter API](#limiter-api)\r\n- [插件](#插件)\r\n  - [列表](#列表)\r\n  - [使用插件](#使用插件)\r\n- [贡献](#贡献)\r\n\r\n## 安装\r\n\r\ntnpm\r\n\r\n``` console\r\n$ tnpm install @dvsantd/polaris\r\n```\r\n\r\nyarn\r\n\r\n``` console\r\n$ yarn add @dvsantd/polaris --registry=https://mirrors.dvsantd.com/npm/\r\n```\r\n\r\n## 例子\r\n\r\n查询被调服务特定地址：\r\n\r\n``` ts\r\nimport { Consumer } from \"@dvsantd/polaris\";\r\nconst consumer = new Consumer();\r\nconst response = await (consumer.select(\"namespace\", \"service\"));\r\nif (response) {\r\n  const { instance: { host, port }} = response;\r\n  /**\r\n   * 通过 host, port 进行调用，\r\n   * 并调用 `update` 上报调用结果\r\n   */\r\n  response.update(success, cost, code);\r\n}\r\n```\r\n\r\n## 使用\r\n\r\n### 运行模式\r\n\r\n模块支持 `Server` 与 `Agent`（暂未上线） 两种运行模式。\r\n\r\n| 模式 | 优势 | 权衡\r\n|---------|------------|-----------\r\n| Server(default) | 不需要部署 Agent<br />可替换不同类型插件<br />拥有更多配置<br />更好的性能 | 不能跨进程统计调用状态\r\n| Agent           | 逻辑简单<br />支持跨进程统计调用状态 | 需要部署 Agent<br />可配置项较少\r\n\r\n> 我应该如何选择运行模式？\r\n>\r\n> __在绝大多数情况下，直接使用默认的 `Server` 模式即可。__\r\n>\r\n> 由于模块只统计当前进程内的调用状态，如果服务调用量极少而又启动了 _多进程_ 负载均衡时，\r\n> 存在无法及时对实例进行调整（如屏蔽熔断）的可能，此时如果服务关心调用成功率，可以使用 `Agent` 模式。\r\n\r\n具体切换方式可详见 [名字服务插件](./plugins#名字服务插件) 。\r\n\r\n### 公共类型\r\n\r\n为了便于描述（表达）北极星组件的调用与返回结构，模块定义了如下几种数据类型：\r\n\r\n- [实例](#实例)\r\n- [位置](#位置)\r\n- [元数据](#元数据)\r\n\r\n#### 实例\r\n\r\n实例 `Instance` 类型描述了服务节点详细信息，信息由静态与动态成员组成：\r\n\r\n* 静态部分：\r\n  * id: 唯一 ID\r\n  * vpc_id: 腾讯云 VPC Id\r\n  * host: IP 或域名\r\n  * port: 端口号\r\n  * protocol: 协议信息\r\n  * staticWeight: 静态权重值, 取值 ∈ [0-1000]\r\n  * metadata: 元数据信息\r\n  * priority: 优先级\r\n  * version: 版本号\r\n  * logicSet: 逻辑区域\r\n  * location: 地理位置\r\n* 动态部分：\r\n  * dynamicWeight: 动态权重值\r\n  * status: 当前状态\r\n\r\n两个实例对象在进行比较时，直接比较 `Instance.id` 是否相同。_也就是说，相同实例的 `id` 必须相同_。\r\n\r\n##### 实例状态\r\n\r\n实例状态 `InstanceStatus` 描述了实例当前所处的状态：\r\n\r\n* Normal: 正常\r\n* HalfOpen: 半打开，各周期只选出极少次，负责探活\r\n* HalfClose: 半关闭，不在任何模块中被选出，但计算调用结果\r\n* Fused: 熔断，不在任何模块中被选出\r\n\r\n各状态间迁移关系，可查看插件节 - [实例状态迁移](#实例状态迁移)\r\n\r\n#### 位置\r\n\r\n位置 `Location` 描述了一个特定的（地理）位置信息，其中包含：\r\n\r\n* region\r\n* zone\r\n* campus(idc)\r\n\r\n两个位置在比较时，按照范围由小至大进行匹配，`campus` --> `zone` --> `region`\r\n\r\n一般用于就近调用等要求匹配位置的场景。\r\n\r\n#### 元数据\r\n\r\n元数据 `Metadata` 以 {[key: string]: string} 形式存储特定对象（如实例对象）的描述信息。\r\n\r\n一般用于规则路由等需进行对象筛选的场景。\r\n\r\n### Consumer API\r\n\r\n``` ts\r\nimport { Consumer } from \"@dvsantd/polaris\"\r\n```\r\n\r\n供服务调用方使用。\r\n\r\n通过提供的主调（可选）与被调服务信息，按规则选出被调服务的一个特定实例或返回所有被调服务实例。\r\n\r\n#### new Consumer(service, plugins, options)\r\n\r\n构造 `Consumer` 对象，用于获取被调方特定实例。\r\n\r\n* service: 主调方服务信息或服务名（可选）\r\n* plugins: 插件列表（可选）\r\n* options: 配置参数（可选）\r\n\r\n__请注意：不要每次调用都构造一个 `Consumer` 对象，这样不仅会造成性能损耗，同时会导致无法按预期逻辑处理。如果你不得不这样做，请在使用完 `Consumer` 对象后调用 `dispose()` 接口将其释放。__\r\n\r\n#### select(...)\r\n\r\n获取被调服务中的一个特定实例，并返回上报对象。\r\n\r\n``` ts\r\nconst response = await consumer.select(namespace, service, metadata, args);\r\n```\r\n\r\n或\r\n\r\n``` ts\r\nconst response = await consumer.select(service, metadata, args);\r\n```\r\n\r\n* namespace: 被调服务名字空间（可选）\r\n* service: 被调服务名\r\n* metadata: 主调方服务元数据（可选）\r\n* args: 本次调用附加参数（可选），在特定负载均衡（如一致性哈希）插件中使用。\r\n\r\n`response.instance` 即为选出的被调服务的特定实例。\r\n\r\n请保留 `select(...)` 接口返回的 `response` 对象，以便在调用完成后进行结果上报：\r\n\r\n``` ts\r\nresponse.update(success, cost, code);\r\n```\r\n\r\n* success: 是否调用成功\r\n* cost: 调用耗时（可选，默认为 0，单位为毫秒）\r\n* code: 返回码（可选）\r\n\r\n__请注意：无论是否调用成功，在调用完成后一定要上报调用结果，否则模块将无法对实例进行动态调整。__\r\n\r\n#### list(...)\r\n\r\n获取被调方全部服务实例。\r\n\r\n``` ts\r\nconst instances = await consumer.list(namespace, service);\r\n```\r\n\r\n或\r\n\r\n``` ts\r\nconst instances = await consumer.list(service);\r\n```\r\n\r\n* namespace: 被调服务名字空间（可选）\r\n* service: 被调服务名\r\n\r\n`instances` 即为被调方全部服务实例。\r\n\r\n#### update(...)\r\n\r\n强制刷新缓存。\r\n\r\n``` ts\r\nconst hasUpdated = await consumer.update(namespace, service, type);\r\n```\r\n\r\n* namespace: 被调服务名字空间\r\n* service: 被调服务名\r\n* type: 数据存储类别，为 RegistryCategory 枚举\r\n\r\n如存在更新，则调用结果为 `true`\r\n\r\n_请留意：一般情况下，请同时更新 `RegistryCategory.Instance` 与 `RegistryCategory.Rule`。_\r\n\r\n#### dispose()\r\n\r\n释放掉 `Consumer` 对象，在内部会释放掉相关的缓存和 socket 连接。\r\n\r\n__请注意：调用 `dispose()` 后，再调用 `Consumer` 对象的其他方法会抛出异常。__\r\n\r\n### Provider API\r\n\r\n供服务提供方使用。\r\n\r\n提供服务注册（注销）、心跳上报等能力。\r\n\r\n#### new Provider(plugins)\r\n\r\n构造 `Provider` 对象，用于获取被调方特定实例。\r\n\r\n* plugins: 插件列表（可选）\r\n\r\n__请注意：不要每次调用都构造一个 `Provider` 对象，这样会造成性能损耗。__\r\n\r\n#### 服务注册\r\n\r\n``` ts\r\nconst response = await provider.register(namespace, service, token, instance, options);\r\n```\r\n\r\n* namespace: 命名空间\r\n* service: 服务名\r\n* token: 服务 Token 用来鉴权\r\n* instance: 待注册的实例\r\n* options: 注册选项（可选）\r\n\r\n可通过 `response` 对注册的服务进行操作： \r\n\r\n* id: 获取注册的实例 `id`\r\n* unregister(): 服务注销\r\n* heartbeat(): 心跳上报\r\n\r\n#### 服务注销\r\n\r\n``` ts\r\nconst success = await provider.unregister(id, token);\r\n```\r\n\r\n* id: 实例 ID\r\n* token: 服务 Token 用来鉴权\r\n\r\n或\r\n\r\n``` ts\r\nconst success = await provider.unregister(namespace, service, host, port, token);\r\n```\r\n\r\n* namespace: 命名空间\r\n* service: 服务名\r\n* host: 节点 IP 或者域名\r\n* port: 节点端口号\r\n* token: 服务 Token 用来鉴权\r\n\r\n可通过 `success` 判断注册是否成功。\r\n\r\n#### 心跳上报\r\n\r\n``` ts\r\nconst success = await provider.heartbeat(id, token);\r\n```\r\n\r\n* id: 实例唯一 ID\r\n* token: 服务 Token 用来鉴权\r\n\r\n或\r\n\r\n``` ts\r\nconst success = await provider.heartbeat(namespace, service, host, port, token)\r\n```\r\n\r\n* namespace: 命名空间\r\n* service: 服务名\r\n* host: 节点 IP 或者域名\r\n* port: 节点端口号\r\n* token: 服务 Token 用来鉴权\r\n\r\n可通过 `success` 判断注册是否成功。\r\n\r\n### Limiter API\r\n\r\n提供流量控制（整形）能力。\r\n\r\n#### new Limiter(plugins, options)\r\n\r\n构造 `Limiter` 对象。\r\n\r\n* plugins: 插件列表（可选）\r\n* options: 配置参数（可选）\r\n\r\n__请注意：不要每次调用都构造一个 `Limiter` 对象，这样不仅会造成性能损耗，同时会导致无法按预期逻辑处理。__\r\n\r\n#### 配额申请\r\n\r\n``` ts\r\nconst response = await limiter.acquire(namespace, service, amount, cluster, labels, id)\r\n```\r\n\r\n* namespace: 命名空间\r\n* service: 服务名\r\n* amount: 申请配额的数量\r\n* cluster: 集群名（可选）\r\n* labels: 标签集合（可选）\r\n* id: 上次调用返回 ID（对应 `response.id`），用于二次获取配额时提升性能（可选）\r\n\r\n`response.quotas` 即为申请的配额列表，而配额是否申请成功需等待其状态变更：\r\n\r\n``` ts\r\nresponse.quotas[i].then((release) => { /** 配额申请成功 */ }, (err) => { /** 配额申请失败 */ });\r\n```\r\n\r\n当针对并发数进行限流时，在配额使用完成后，需调用 `release()` 方法释放对于配额的占用。\r\n\r\n## 插件\r\n\r\n### 列表\r\n\r\n- [名字服务插件](./PLUGINS.md#名字服务插件)\r\n  - [Polaris Server](./PLUGINS.md#polaris-server)\r\n  - [Local Server](./PLUGINS.md#local-server)\r\n- [本地仓库插件](./PLUGINS.md#本地仓库插件)\r\n  - [Memory Only](./PLUGINS.md#memory-only)\r\n- [服务路由插件](./PLUGINS.md#服务路由插件)\r\n  - [Polaris Rule Router](./PLUGINS.md#polaris-rule-router)\r\n  - [Polaris Nearby Router](./PLUGINS.md#polaris-nearby-router)\r\n  - [tRPC Env Router](./PLUGINS.md#trpc-env-router)\r\n  - [tRPC Set Router](./PLUGINS.md#trpc-set-router)\r\n- [负载均衡插件](./PLUGINS.md#负载均衡插件)\r\n  - [最早截止时间优先](./PLUGINS.md#earliest-deadline-first-round-robin)\r\n  - [平滑加权轮询](./PLUGINS.md#smooth-weighted-round-robin)\r\n  - [简单权重轮询](./PLUGINS.md#weighted-round-robin)\r\n  - [权重随机](./PLUGINS.md#weight-random)\r\n  - [一致性哈希](./PLUGINS.md#consistent-hash)\r\n- [节点熔断插件](./PLUGINS.md#节点熔断插件)\r\n  - [Polaris Breaker](./PLUGINS.md#polaris-breaker)\r\n- [权重调整插件](./PLUGINS.md#权重调整插件)\r\n  - [Polaris Adjuster](./PLUGINS.md#polaris-adjuster)\r\n- [健康探测插件](./PLUGINS.md#健康探测插件)\r\n- [限流服务插件](./PLUGINS.md#限流服务插件)\r\n- [流量整形插件](./PLUGINS.md#流量整形插件)\r\n  - [Unirate Shaping](./PLUGINS.md#unirate-shaping)\r\n  - [Warm Up Shaping](./PLUGINS.md#warm-up-shaping)\r\n- [统计上报插件](./PLUGINS.md#统计上报插件)\r\n- [日志跟踪插件](./PLUGINS.md#日志跟踪插件)\r\n  - [Console Tracer](./PLUGINS.md#console-tracer)\r\n\r\n### 使用插件\r\n\r\n所有的内置插件被定义为实现了特定插件接口的 `class`。**缺省情况下，`new Consumer()` 时构造函数内部会使用默认参数实例化一系列插件实例**。如果需要替换掉默认的插件或其实例化的参数，可以在 `new Consumer()` 时直接传入特定插件的实例。部分插件支持调用时参数，可以在调用 `select()` 方法时传入。\r\n\r\n以负载均衡（一致性哈希）为例，其初始化和传参方法如下：\r\n\r\n```ts\r\nimport { Consumer, HashRingLoadBalancer, plugins } from  \"@dvsantd/polaris\";\r\n\r\nconst consumer = new Consumer({\r\n  [plugins.PluginType.LoadBalancer]: new HashRingLoadBalancer({\r\n    algorithm: 'md5'\r\n  })\r\n});\r\n\r\n(async () => {\r\n  await consumer.select(\"namespace\", \"service\", metadata, {\r\n    [plugins.PluginType.LoadBalancer]: 'group/project'\r\n  })\r\n})();\r\n```\r\n\r\n详情请看 [插件](./PLUGINS.md)\r\n\r\n## 贡献\r\n\r\n我们十分期待您的贡献，更多详情请参考 [CONTRIBUTING.md](./CONTRIBUTING.md)\r\n","readmeFilename":"README.md"}