Dapr 是一个可移植的、事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的、无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架。Dapr 确保开发人员专注于编写业务逻辑,不必分神解决分布式系统难题,从而显著提高了生产力。Dapr 降低了构建微服务架构类现代云原生应用的门槛。
目录
- 系列
- JavaScript
- 安装
- 结构
- Client
- 介绍
- 前提条件
- 安装和导入 Dapr 的 JS SDK
- 运行
- 使用 HTTP(默认)
- 使用 gRPC
- 代理请求
- 创建代理
- 幕后(技术工作)
- 构建块
- 调用 API
- 状态管理 API
- 查询状态 API
- 发布订阅 API
- 绑定 API
- Secret API
- 配置 API
- Server
- 介绍
- 前提条件
- 安装和导入 Dapr 的 JS SDK
- 运行
- 使用 HTTP(默认)
- 使用 gRPC
- 构建块
- 调用 API
- 发布订阅 API
- 绑定 API
- 配置 API
- Actors
- 前提条件
- 场景
- Actor 接口
- Actor 实现
- 注册 Actor
- 调用 Actor 方法
- 将状态与 Actor 一起使用
- Actor 计时器和提醒器
- Actor Timers
- Actor Reminders
- Logging
- 介绍
- 配置日志级别
- Dapr Client
- DaprServer
- 自定义 LoggerService
- 官方示例代码库
系列
- Dapr 与 NestJs ,实战编写一个 Pub & Sub 装饰器
- NodeJS 基于 Dapr 构建云原生微服务应用,从 0 到 1 快速上手指南
- 本地使用 Docker Compose 与 Nestjs 快速构建基于 Dapr 的 Redis 发布/订阅分布式应用
JavaScript
用于在 JavaScript 和 TypeScript 中构建 Dapr 应用程序的客户端库。该客户端抽象了公共 Dapr API,例如服务到服务调用、状态管理、发布/订阅、机密等,并为构建应用程序提供了一个简单、直观的 API。
安装
要开始使用 Javascript SDK,请从 NPM 安装 Dapr JavaScript SDK 包:
代码语言:javascript复制npm install --save @dapr/dapr
⚠️ dapr-client 现在已弃用。请参阅#259 了解更多信息。
- https://github.com/dapr/js-sdk/issues/259
结构
Dapr Javascript SDK 包含两个主要组件:
- DaprServer: 管理所有 Dapr sidecar 到应用程序的通信。
- DaprClient: 管理所有应用程序到 Dapr sidecar 的通信。
上述通信可以配置为使用 gRPC 或 HTTP 协议。
Client
介绍
Dapr Client 允许您与 Dapr Sidecar 通信并访问其面向客户端的功能,例如发布事件、调用输出绑定、状态管理、Secret 管理等等。
前提条件
- Dapr CLI 已安装
- https://docs.dapr.io/getting-started/install-dapr-cli/
- 初始化 Dapr 环境
- https://docs.dapr.io/getting-started/install-dapr-selfhost/
- 最新 LTS 版本的 Node 或更高版本
- https://nodejs.org/en/
安装和导入 Dapr 的 JS SDK
- 使用 npm 安装 SDK:
npm i @dapr/dapr --save
- 导入库:
import { DaprClient, DaprServer, HttpMethod, CommunicationProtocolEnum } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server
// HTTP Example
const client = new DaprClient(daprHost, daprPort);
// GRPC Example
const client = new DaprClient(daprHost, daprPort, CommunicationProtocolEnum.GRPC);vvvvvvvvv
运行
要运行示例,您可以使用两种不同的协议与 Dapr sidecar 交互:HTTP(默认)或 gRPC。
使用 HTTP(默认)
代码语言:javascript复制import { DaprClient } from "@dapr/dapr";
const client = new DaprClient(daprHost, daprPort);
代码语言:javascript复制# Using dapr run
dapr run --app-id example-sdk --app-protocol http -- npm run start
# or, using npm script
npm run start:dapr-http
使用 gRPC
由于 HTTP 是默认设置,因此您必须调整通信协议以使用 gRPC。您可以通过向客户端或服务器构造函数传递一个额外的参数来做到这一点。
代码语言:javascript复制import { DaprClient, CommunicationProtocol } from "@dapr/dapr";
const client = new DaprClient(daprHost, daprPort, CommunicationProtocol.GRPC);
代码语言:javascript复制# Using dapr run
dapr run --app-id example-sdk --app-protocol grpc -- npm run start
# or, using npm script
npm run start:dapr-grpc
代理请求
通过代理请求,我们可以利用 Dapr 通过其 sidecar 架构带来的独特功能,例如服务发现、日志记录等,使我们能够立即“升级”我们的 gRPC 服务。gRPC 代理的这一特性在community call 41 中得到了展示。
community call 41https://www.youtube.com/watch?v=B_vkXqptpXY&t=71s
创建代理
要执行 gRPC 代理,只需调用 client.proxy.create() 方法创建一个代理:
代码语言:javascript复制// As always, create a client to our dapr sidecar
// this client takes care of making sure the sidecar is started, that we can communicate, ...
const clientSidecar = new DaprClient(daprHost, daprPort, CommunicationProtocolEnum.GRPC);
// Create a Proxy that allows us to use our gRPC code
const clientProxy = await clientSidecar.proxy.create<GreeterClient>(GreeterClient);
我们现在可以调用 GreeterClient 接口中定义的方法(在本例中来自 Hello World 示例)
- https://github.com/grpc/grpc-go/blob/master/examples/helloworld/helloworld/helloworld.proto
幕后(技术工作)
- gRPC 服务在 Dapr 中启动。我们通过
--app-port
告诉 Dapr 这个 gRPC 服务器在哪个端口上运行,并通过--app-id <APP_ID_HERE>
给它一个唯一的 Dapr 应用 ID - 我们现在可以通过将连接到 Sidecar 的客户端调用 Dapr Sidecar
- 在调用 Dapr Sidecar 时,我们提供了一个名为
dapr-app-id
的元数据键,其中包含在 Dapr 中启动的 gRPC 服务器的值(例如,我们示例中的server
) - Dapr 现在会将调用转发到配置的 gRPC 服务器
构建块
JavaScript 客户端 SDK 允许您与专注于 Client to Sidecar 功能的所有 Dapr 构建块进行交互。
- https://docs.dapr.io/developing-applications/building-blocks/
调用 API
调用一个服务
代码语言:javascript复制import { DaprClient, HttpMethod } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient(daprHost, daprPort);
const serviceAppId = "my-app-id";
const serviceMethod = "say-hello";
// POST Request
const response = await client.invoker.invoke(serviceAppId , serviceMethod , HttpMethod.POST, { hello: "world" });
// GET Request
const response = await client.invoker.invoke(serviceAppId , serviceMethod , HttpMethod.GET);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
有关服务调用的完整指南,请访问 How-To: Invoke a service。https://docs.dapr.io/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services/
状态管理 API
保存、获取和删除应用程序状态
代码语言:javascript复制import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient(daprHost, daprPort);
const serviceStoreName = "my-state-store-name";
// Save State
const response = await client.state.save(serviceStoreName, [
{
key: "first-key-name",
value: "hello"
},
{
key: "second-key-name",
value: "world"
}
]);
// Get State
const response = await client.state.get(serviceStoreName, "first-key-name");
// Get Bulk State
const response = await client.state.getBulk(serviceStoreName, ["first-key-name", "second-key-name"]);
// State Transactions
await client.state.transaction(serviceStoreName, [
{
operation: "upsert",
request: {
key: "first-key-name",
value: "new-data"
}
},
{
operation: "delete",
request: {
key: "second-key-name"
}
}
]);
// Delete State
const response = await client.state.delete(serviceStoreName, "first-key-name");
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
有关状态操作的完整列表,请访问 How-To: Get & save state。https://docs.dapr.io/developing-applications/building-blocks/state-management/howto-get-save-state/
查询状态 API
代码语言:javascript复制import { DaprClient } from "@dapr/dapr";
async function start() {
const client = new DaprClient(daprHost, daprPort);
const res = await client.state.query("state-mongodb", {
filter: {
OR: [
{
EQ: { "person.org": "Dev Ops" }
},
{
"AND": [
{
"EQ": { "person.org": "Finance" }
},
{
"IN": { "state": ["CA", "WA"] }
}
]
}
]
},
sort: [
{
key: "state",
order: "DESC"
}
],
page: {
limit: 10
}
});
console.log(res);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
发布订阅 API
发布消息
代码语言:javascript复制import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient(daprHost, daprPort);
const pubSubName = "my-pubsub-name";
const topic = "topic-a";
const message = { hello: "world" }
// Publish Message to Topic
const response = await client.pubsub.publish(pubSubName, topic, message);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
订阅消息
代码语言:javascript复制import { DaprServer } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server "
async function start() {
const server = new DaprServer(serverHost, serverPort, daprHost, daprPort);
const pubSubName = "my-pubsub-name";
const topic = "topic-a";
// Configure Subscriber for a Topic
await server.pubsub.subscribe(pubSubName, topic, async (data: any) => console.log(`Got Data: ${JSON.stringify(data)}`));
await server.start();
}
有关状态操作的完整列表,请访问 How-To: Publish and subscribe。https://docs.dapr.io/developing-applications/building-blocks/pubsub/howto-publish-subscribe/
绑定 API
调用输出绑定
代码语言:javascript复制import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient(daprHost, daprPort);
const bindingName = "my-binding-name";
const bindingOperation = "create";
const message = { hello: "world" };
const response = await client.binding.send(bindingName, bindingOperation, message);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
有关输出绑定的完整指南,请访问 How-To: Use bindings。https://docs.dapr.io/developing-applications/building-blocks/bindings/howto-bindings/
Secret API
检索 secret
代码语言:javascript复制import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
async function start() {
const client = new DaprClient(daprHost, daprPort);
const secretStoreName = "my-secret-store";
const secretKey = "secret-key";
// Retrieve a single secret from secret store
const response = await client.secret.get(secretStoreName, secretKey);
// Retrieve all secrets from secret store
const response = await client.secret.getBulk(secretStoreName);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
有关 secrets 的完整指南,请访问 How-To: Retrieve Secrets。https://docs.dapr.io/developing-applications/building-blocks/secrets/howto-secrets/
配置 API
获取配置 key
代码语言:javascript复制import { DaprClient } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprAppId = "example-config";
async function start() {
const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT);
const config = await client.configuration.get('config-store', ['key1', 'key2']);
console.log(config);
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
Server
介绍
Dapr Server 将允许您接收来自 Dapr Sidecar 的通信并访问其面向服务器的功能,例如:订阅事件、接收输入绑定等等。
前提条件
- Dapr CLI 已安装
- https://docs.dapr.io/getting-started/install-dapr-cli/
- 初始化 Dapr 环境
- https://docs.dapr.io/getting-started/install-dapr-selfhost/
- 最新 LTS 版本的 Node 或更高版本
- https://nodejs.org/en/
安装和导入 Dapr 的 JS SDK
- 使用
npm
安装 SDK:
npm i @dapr/dapr --save
- 导入库:
import { DaprClient, DaprServer, HttpMethod, CommunicationProtocolEnum } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server
// HTTP Example
const client = new DaprClient(daprHost, daprPort);
// GRPC Example
const client = new DaprClient(daprHost, daprPort, CommunicationProtocolEnum.GRPC);
运行
要运行示例,您可以使用两种不同的协议与 Dapr sidecar 交互:HTTP(默认)或 gRPC。
使用 HTTP(默认)
代码语言:javascript复制import { DaprServer } from "@dapr/dapr";
const server= new DaprServer(appHost, appPort, daprHost, daprPort);
// initialize subscribtions, ... before server start
// the dapr sidecar relies on these
await server.start();
代码语言:javascript复制# Using dapr run
dapr run --app-id example-sdk --app-port 50051 --app-protocol http -- npm run start
# or, using npm script
npm run start:dapr-http
ℹ️ Note:这里需要 app-port,因为这是我们的服务器需要绑定的地方。Dapr 将在完成启动之前检查应用程序是否绑定到此端口。
使用 gRPC
由于 HTTP 是默认设置,因此您必须调整通信协议以使用 gRPC。您可以通过向客户端或服务器构造函数传递一个额外的参数来做到这一点。
代码语言:javascript复制import { DaprServer, CommunicationProtocol } from "@dapr/dapr";
const server = new DaprServer(appHost, appPort, daprHost, daprPort, CommunicationProtocol.GRPC);
// initialize subscribtions, ... before server start
// the dapr sidecar relies on these
await server.start();
代码语言:javascript复制# Using dapr run
dapr run --app-id example-sdk --app-port 50051 --app-protocol grpc -- npm run start
# or, using npm script
npm run start:dapr-grpc
ℹ️ Note:这里需要 app-port,因为这是我们的服务器需要绑定的地方。Dapr 将在完成启动之前检查应用程序是否绑定到此端口。
构建块
JavaScript Server SDK 允许您与专注于 Sidecar 到 App 功能的所有 Dapr 构建块进行交互。
调用 API
监听调用
代码语言:javascript复制import { DaprServer } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server "
async function start() {
const server = new DaprServer(serverHost, serverPort, daprHost, daprPort);
await server.invoker.listen('hello-world', mock, { method: HttpMethod.GET });
// You can now invoke the service with your app id and method "hello-world"
await server.start();
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
有关服务调用的完整指南,请访问 How-To: Invoke a service。https://docs.dapr.io/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services/
发布订阅 API
订阅消息
代码语言:javascript复制import { DaprServer } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server "
async function start() {
const server = new DaprServer(serverHost, serverPort, daprHost, daprPort);
const pubSubName = "my-pubsub-name";
const topic = "topic-a";
// Configure Subscriber for a Topic
await server.pubsub.subscribe(pubSubName, topic, async (data: any) => console.log(`Got Data: ${JSON.stringify(data)}`));
await server.start();
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
有关状态操作的完整列表,请访问 How-To: Publish and subscribe。https://docs.dapr.io/developing-applications/building-blocks/pubsub/howto-publish-subscribe/
绑定 API
接收一个输入绑定
代码语言:javascript复制import { DaprServer } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
const serverHost = "127.0.0.1";
const serverPort = "5051";
async function start() {
const server = new DaprServer(serverHost, serverPort, daprHost, daprPort);
const bindingName = "my-binding-name";
const response = await server.binding.receive(bindingName, async (data: any) => console.log(`Got Data: ${JSON.stringify(data)}`));
await server.start();
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
有关输出绑定的完整指南,请访问 How-To: Use bindings。https://docs.dapr.io/developing-applications/building-blocks/bindings/howto-bindings/