Dapr 是一个可移植的、事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的、无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架。Dapr 确保开发人员专注于编写业务逻辑,不必分神解决分布式系统难题,从而显著提高了生产力。Dapr 降低了构建微服务架构类现代云原生应用的门槛。

系列

Dapr JavaScript SDK

用于在 JavaScript 和 TypeScript 中构建 Dapr 应用程序的客户端库。 该客户端抽象了公共 Dapr API,例如服务到服务调用、状态管理、发布/订阅、Secret 等,并为构建应用程序提供了一个简单、直观的 API。

安装

要开始使用 Javascript SDK,请从 NPM 安装 Dapr JavaScript SDK 包:

npm install --save @dapr/dapr

️ dapr-client 现在已弃用。 请参阅#259 了解更多信息。

结构

Dapr Javascript SDK 包含两个主要组件:

  • DaprServer: 管理所有 Dapr sidecar 到应用程序的通信。
  • DaprClient: 管理所有应用程序到 Dapr sidecar 的通信。

上述通信可以配置为使用 gRPC 或 HTTP 协议。

实战

创建一个小应用程序来生成有关网站中用户行为的统计信息。

Demo 源码

https://github.com/Hacker-Linner/dapr-nestjs-jssdk-decorator

准备环境和项目结构

npm install -g @nestjs/cli
nest new api
mv api nest-dapr
cd nest-dapr
nest generate app page-view
npm install dapr-client
wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash

创建一个 decorators.ts 文件(apps/shared/decorators.ts),这样所有微服务都可以从我们即将编写的基础架构中受益。

注入 Dapr 赖项

注入 DaprClient 和 DaprServer,我们需要提供它们到 nest.js

在 app.module.ts 中让我们注册 DaprClient:

providers: [
...
{
provide: DaprClient,
useValue: new DaprClient()
}
]

在 page-view.module.ts 中以同样的方式添加 DaprServer:

providers: [
...
{
provide: DaprServer,
useValue: new DaprServer()
}
]

配置 Dapr 组件(rabbitMQ)

用 docker compose 启动 rabbitmq:

version: '3.9'
services:
pubsub:
image: rabbitmq:3-management-alpine
container_name: 'pubsub'
ports:
- 5674:5672
- 15674:15672 #web port

我们还需要配置 Dapr 组件。在根文件夹中创建一个 component/pubsub.yml:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
namespace: default
spec:
type: pubsub.rabbitmq
version: v1
metadata:
- name: host
value: 'amqp://guest:guest@localhost:5674'

每个 Dapr 微服务都需要自己的 config。

api/dapr/config.yml:

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: api
namespace: default

page-view/dapr/config.yml:

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: page-view
namespace: default

API/Gateway 服务

app.controller.ts 中,我们将公开一个简单的 API/add-page-view

 @Post('/add-page-view')
async prderAdd(@Body() pageViewDto: PageViewDto): Promise<void> {
try {
console.log(pageViewDto);
await this.daprClient.pubsub.publish('pubsub', 'page-view-add', pageViewDto);
} catch (e) {
console.log(e);
}
}

内部监听微服务

在我们将数据发布到队列之后,我们需要监听它并调用它:

在 page-view.controller.ts 添加:

@DaprPubSubSubscribe('pubsub', 'add')
addPageView(data: PageViewDto) {
console.log(`addPageView executed with data: ${JSON.stringify(data)}`);
this.data.push(data);
}

注意我们现在需要创建的新装饰器:@DaprPubSubscribe

@DaprPubSubscribe 装饰器

在 shared/decorators.ts 中:

import { INestApplication } from '@nestjs/common';
import { DaprServer } from 'dapr-client'; export type PubsubMap = {
[pubSubName: string]: {
topic: string;
target: any;
descriptor: PropertyDescriptor;
};
};
export const DAPR_PUB_SUB_MAP: PubsubMap = {};
export const DaprPubSubSubscribe = (
pubSubName: string,
topic: string,
): MethodDecorator => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
DAPR_PUB_SUB_MAP[pubSubName] = {
topic,
target,
descriptor,
};
return descriptor;
};
}; export const useDaprPubSubListener = async (app: INestApplication) => {
const daprServer = app.get(DaprServer); for (const pubSubName in DAPR_PUB_SUB_MAP) {
const item = DAPR_PUB_SUB_MAP[pubSubName];
console.log(
`Listening to the pubsub name - "${pubSubName}" on topic "${item.topic}"`,
);
await daprServer.pubsub.subscribe(
pubSubName,
item.topic,
async (data: any) => {
const targetClassImpl = app.get(item.target.constructor);
await targetClassImpl[item.descriptor.value.name](data);
},
);
}
};

运行应用程序

运行:

docker-compose up -d # 启动 rabbitmq
npm run dapr:api:dev # 启动 api/gateway
npm run page-view:dev # 启动内部微服务监听 dapr rabbitmq 队列

执行请求:

curl --location --request POST 'http://localhost:7001/v1.0/invoke/api/method/statistics/add-page-view' \
--header 'Content-Type: application/json' \
--data-raw '{
"pageUrl" : "https://test.com/some-page",
"userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"
}'

Dapr 与 NestJs ,实战编写一个 Pub & Sub 装饰器的更多相关文章

  1. C#编写一个简易的文件管理器

    编写一个简易的文件管理器,通过本次实验,练习 TreeView.ListView 和SplitContainer 控件的使用,同时熟悉 C#文件系统的操作方法以及 File 类和 Directory类 ...

  2. 一个关于python装饰器参数的问题

    看到廖雪峰python教程上,python装饰器一章 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3 ...

  3. 如何写一个Python万能装饰器,既可以装饰有参数的方法,也可以装饰无参数方法,或者有无返回值都可以装饰

    Python中的装饰器,可以有参数,可以有返回值,那么如何能让这个装饰器既可以装饰没有参数没有返回值的方法,又可以装饰有返回值或者有参数的方法呢?有一种万能装饰器,代码如下: def decorate ...

  4. Python核心技术与实战——十四|Python中装饰器的使用

    我在以前的帖子里讲了装饰器的用法,这里我们来具体讲一讲Python中的装饰器,这里,我们从前面讲的函数,闭包为切入点,引出装饰器的概念.表达和基本使用方法.其次,我们结合一些实际工程中的例子,以便能再 ...

  5. 简化ETL工作,编写一个Canal胶水层

    前提 这是一篇憋了很久的文章,一直想写,却又一直忘记了写.整篇文章可能会有点流水账,相对详细地介绍怎么写一个小型的"框架".这个精悍的胶水层已经在生产环境服役超过半年,这里尝试把耦 ...

  6. 装饰器模式(Decorator)——深入理解与实战应用

    本文为原创博文,转载请注明出处,侵权必究! 1.初识装饰器模式 装饰器模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能.其结构图如下: Component为统一接口,也是装饰类和被装 ...

  7. python :编写装饰器

    简单装饰器 def log_time(func): # 此函数的作用时接受被修饰的函数的引用test,然后被内部函数使用 def make_decorater(): print('现在开始装饰') f ...

  8. 编译原理实战——使用Lex/Flex进行编写一个有一定词汇量的词法分析器

    编译原理实战--使用Lex/Flex进行编写一个有一定词汇量的词法分析器 by steve yu 2019.9.30 参考文档:1.https://blog.csdn.net/mist14/artic ...

  9. C# 基础知识系列- 17 实战篇 编写一个小工具(1)

    0. 前言 这是对C# 基础系列的一个总结,现在我们利用之前学到的知识做一个小小的工具来给我们使用. 如果有看过IO篇的小伙伴,应该有印象.当时我提过一个场景描述,我们在平时使用系统的时候,经常会为了 ...

随机推荐

  1. zabbix 线路质量监控自定义python模块(Mysql版),多线程(后来发现使用协程更好)降低系统消耗

    之前零零碎碎写了一些zabbix 线路监控的脚本,工作中agnet较多,每条线路监控需求不一致,比较杂乱,现在整理成一个py模块,集合之前的所有功能 环境 python3.6以上版本,pip3(pip ...

  2. 使用 VS Code + Markdown 编写 PDF 文档

    背景介绍 作为一个技术人员,基本都需要编写技术相关文档,而且大部分技术人员都应该掌握 markdown 这个技能,使用 markdown 来编写并生成 PDF 文档将会是一个不错的体验,以下就介绍下如 ...

  3. MySQL执行计划explain

    一.简介 分析查询慢的原因,在查询语句前加explain即可.如: 二.输出格式 2.0 测试数据 # 表user_info CREATE TABLE `user_info` ( `id` bigin ...

  4. Node.js的多版本管理工具 gnvm(win环境)的详细安装教程(图解步骤、通俗易懂、亲测有效)

    前言 本篇随笔主要写了如何安装并使用node多版本管理工具gnvm(windowns环境下) 作为自己对多版本工具gnvm知识的总结与笔记. 百度云盘gnvm应用程序包 获取链接(个人应用地址如下): ...

  5. 什么是Netty编解码,Netty编解码器有哪些?Protostuff怎么使用?

    哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 书接上回,昨天下雨没怎么上街上 ...

  6. JS基础二--字面量和变量

       /*       字面量,都是一些不可改变的值,       比如:1 2 3 4 5       字面量都是可以直接使用,但是我们一般不会直接使用字面量.       变量,变量可以用来保存字 ...

  7. 《HALCON数字图像处理》第六章笔记

    目录 第六章 图像增强 图像增强的概念和分类 灰度变换 直方图处理 图像的平滑 图像的锐化 图像的彩色增强 我在Gitee上建了个仓库,会将学习书本的时候打的一些代码上传上去,笔记中所有代码都在仓库里 ...

  8. 2021.03.20【NOIP提高B组】模拟 总结

    区间 DP 专场:愉快爆炸 T1 题目大意 有 \(n\) 个有颜色的块,连续 \(k\) 个相同颜色的就可以消掉 现在可以在任意位置插入任意颜色的方块,问最少插入多少个可以全部抵消 题解 先把连续的 ...

  9. php 正则获取字符串中的汉字(去除字符串中除汉字外的所有字符)

    preg_match_all('/[\x{4e00}-\x{9fff}]+/u', $list[$i]['iparr'], $matches); $list[$i]['iparr'] = join(' ...

  10. 【.NET 6】多线程的几种打开方式和代码演示

    前言: 多线程无处不在,平常的开发过程中,应该算是最常用的基础技术之一了.以下通过Thread.ThreadPool.再到Task.Parallel.线程锁.线程取消等方面,一步步进行演示多线程的一些 ...