Quarkus Mutiny:异步请求的正确处理方式

quarkus mutiny:异步请求的正确处理方式

Quarkus Mutiny:异步请求的正确处理方式

本文旨在帮助开发者理解如何在 Quarkus 中使用 Mutiny 处理异步请求,特别是当需要等待多个请求完成后再进行下一步操作时。我们将通过示例代码展示如何避免阻塞主线程,以及如何正确地组合多个 Uni 对象,确保在所有依赖的异步操作完成后返回最终结果。同时,强调了在 Quarkus 环境下,避免使用 await().indefinetly 和手动 subscribe() 的重要性。

在使用 Quarkus 和 Mutiny 构建响应式应用时,一个常见的挑战是如何处理多个异步操作,并确保在所有操作完成后再返回结果。例如,你需要调用多个外部 API,并将它们的结果组合起来。直接使用 await().indefinitely 可能会阻塞 Vert.x 的事件循环线程,导致性能问题。手动 subscribe() 在Quarkus中也通常是不需要的,因为Quarkus能够自动处理异步结果。

下面,我们将通过示例代码演示如何正确地处理这种情况。

使用 Uni.combine().all() 组合多个 Uni 对象

假设我们需要调用三个不同的 API 来获取汽车的门、轮子和窗户信息,然后将这些信息组合成一个 Car 对象。

首先,定义获取这些信息的三个方法:

Uni<List> getDoors(String variable1, String variable2, String variable3) {    // 模拟API调用,返回门的列表    return Uni.createFrom().item(List.of(new JsonObjectCar("door1"), new JsonObjectCar("door2")))            .onItem().delayIt().by(Duration.ofMillis(500)); // 模拟延迟}Uni<List> getWheels(String variable1, String variable2, String variable3) {    // 模拟API调用,返回轮子的列表    return Uni.createFrom().item(List.of(new JsonObjectCar("wheel1"), new JsonObjectCar("wheel2")))            .onItem().delayIt().by(Duration.ofMillis(300)); // 模拟延迟}Uni<List> getWindows(String variable1, String variable2, String variable3) {    // 模拟API调用,返回窗户的列表    return Uni.createFrom().item(List.of(new JsonObjectCar("window1"), new JsonObjectCar("window2")))            .onItem().delayIt().by(Duration.ofMillis(700)); // 模拟延迟}class JsonObjectCar {    private String name;    public JsonObjectCar(String name) {        this.name = name;    }    public String getName() {        return name;    }}class Car {    private List doors;    private List wheels;    private List windows;    public void setDoors(List doors) {        this.doors = doors;    }    public void setWheels(List wheels) {        this.wheels = wheels;    }    public void setWindows(List windows) {        this.windows = windows;    }    public List getDoors() {        return doors;    }    public List getWheels() {        return wheels;    }    public List getWindows() {        return windows;    }}

接下来,使用 Uni.combine().all() 将这三个 Uni 对象组合起来:

import io.smallrye.mutiny.Uni;import java.time.Duration;import java.util.List;import javax.ws.rs.GET;import javax.ws.rs.Path;import java.util.Optional;@Path("/api")public class CarResource {    @GET    @Path("/testingAsync")    public Uni testingMutiny() {        String variable1 = "var1";        String variable2 = "var2";        String variable3 = "var3";        Uni<List> carDoorsUni = getDoors(variable1, variable2, variable3);        Uni<List> carWheelsUni = getWheels(variable1, variable2, variable3);        Uni<List> carWindowsUni = getWindows(variable1, variable2, variable3);        return Uni.combine()                .all()                .unis(carDoorsUni, carWheelsUni, carWindowsUni)                .combinedWith(list -> {                    // Result of carDoorsUni                    List carDoors = list.get(0);                    // Result of carWheelsUni                    List carWheels = list.get(1);                    // Result of carWindowsUni                    List carWindows = list.get(2);                    // Create a car instance with the previous results                    Car car = new Car();                    Optional.ofNullable(carDoors).ifPresent(car::setDoors);                    Optional.ofNullable(carWheels).ifPresent(car::setWheels);                    Optional.ofNullable(carWindows).ifPresent(car::setWindows);                    // You can also return a list of cars, but you need to change the return type of testingMutiny to Uni<List>                    return car;                })                .invoke(() -> System.out.println("Okay it worked"));    }    Uni<List> getDoors(String variable1, String variable2, String variable3) {        // 模拟API调用,返回门的列表        return Uni.createFrom().item(List.of(new JsonObjectCar("door1"), new JsonObjectCar("door2")))                .onItem().delayIt().by(Duration.ofMillis(500)); // 模拟延迟    }    Uni<List> getWheels(String variable1, String variable2, String variable3) {        // 模拟API调用,返回轮子的列表        return Uni.createFrom().item(List.of(new JsonObjectCar("wheel1"), new JsonObjectCar("wheel2")))                .onItem().delayIt().by(Duration.ofMillis(300)); // 模拟延迟    }    Uni<List> getWindows(String variable1, String variable2, String variable3) {        // 模拟API调用,返回窗户的列表        return Uni.createFrom().item(List.of(new JsonObjectCar("window1"), new JsonObjectCar("window2")))                .onItem().delayIt().by(Duration.ofMillis(700)); // 模拟延迟    }    class JsonObjectCar {        private String name;        public JsonObjectCar(String name) {            this.name = name;        }        public String getName() {            return name;        }    }    class Car {        private List doors;        private List wheels;        private List windows;        public void setDoors(List doors) {            this.doors = doors;        }        public void setWheels(List wheels) {            this.wheels = wheels;        }        public void setWindows(List windows) {            this.windows = windows;        }        public List getDoors() {            return doors;        }        public List getWheels() {            return wheels;        }        public List getWindows() {            return windows;        }    }}

在这个例子中,Uni.combine().all().unis() 接收一个包含多个 Uni 对象的列表,并返回一个新的 Uni 对象,该对象在所有输入的 Uni 对象都发出值后才发出一个值。combinedWith 方法接收一个函数,该函数将所有输入 Uni 对象发出的值组合成一个结果。

注意事项:

避免阻塞: 不要在 Vert.x 事件循环线程中调用 await().indefinitely 或其他阻塞方法。这会降低应用的响应速度和吞吐量。错误处理: 如果任何一个 Uni 对象发出错误,组合后的 Uni 对象也会发出错误。你可以使用 onFailure() 方法来处理错误。Quarkus 的自动处理: 在 Quarkus 中,通常不需要手动 subscribe() Uni 或 Multi 对象。Quarkus 会自动处理异步结果。线程模型: 了解 Vert.x 的线程模型至关重要。避免在事件循环线程中执行耗时操作。将这些操作 offload 到 worker 线程。

总结

使用 Quarkus Mutiny 处理异步请求的关键在于理解响应式编程的思想,并利用 Mutiny 提供的组合操作符来处理多个异步操作。避免阻塞事件循环线程,并利用 Quarkus 的自动处理能力,可以构建高效、响应迅速的应用程序。Uni.combine().all() 是一个强大的工具,可以帮助你轻松地组合多个 Uni 对象,并在所有操作完成后执行下一步操作。

以上就是Quarkus Mutiny:异步请求的正确处理方式的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/82044.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月16日 00:44:29
下一篇 2025年11月16日 01:25:14

相关推荐

  • Go语言中CSV数据导入MS SQL记录丢失问题的解决方案与最佳实践

    本文深入探讨了go语言在使用`go-odbc`库将csv数据导入ms sql时可能出现的记录丢失问题。通过分析常见症状(如偶发性记录丢失,以及通过添加`fmt.printf()`语句来“解决”问题),文章揭示了其根本原因在于不完善的错误处理、资源管理和eof处理逻辑。教程将提供一套健壮的解决方案,包…

    好文分享 2025年12月16日
    000
  • Golang如何处理网络请求错误

    Go语言处理网络请求错误需检查error值并区分连接错误与状态码错误;2. 使用http.Get或Client.Do后必须检查err,处理超时、DNS解析等底层问题;3. 即使err为nil,也需判断resp.StatusCode是否为2xx,非2xx需读取body并记录错误;4. 应设置http.…

    2025年12月16日
    000
  • Golang如何使用net包进行TCP/UDP通信

    Go语言通过net包实现TCP和UDP编程,支持高性能网络服务。1. TCP通信:使用net.Listen监听端口,Accept接收连接,每个连接由goroutine处理,确保并发;客户端用net.Dial建立连接,收发数据后关闭。2. UDP通信:通过net.ListenPacket或net.Di…

    2025年12月16日
    000
  • 如何在Go语言中正确执行带参数的Shell命令

    本文详细介绍了在go语言中使用`os/exec`包执行shell命令时,如何正确处理命令及其参数。核心在于理解`exec.command`函数的签名,将命令名称和其所有参数作为独立的字符串参数传递,而非将它们拼接成一个长字符串。文章通过示例代码演示了正确的用法,并提供了错误处理、输出捕获以及其他高级…

    2025年12月16日
    000
  • Go语言基准测试的最佳实践与模式

    本文旨在纠正go语言基准测试的常见误解,并提供一套标准且高效的实践方法。我们将深入探讨如何使用`benchmarkxxx`函数结合`go test -bench=.`命令进行性能测试,并介绍一种通过通用基准测试函数减少重复代码的模式,尤其适用于参数略有差异的测试场景,从而确保基准测试的准确性与可维护…

    2025年12月16日
    000
  • Golang包并发使用模式:何时使用Goroutines?

    在使用go语言标准库或第三方包时,开发者常困惑何时应显式使用`go`关键字启动goroutine。核心原则是,除非文档明确说明,否则默认假定函数是同步执行且不具备并发安全性。异步模式通常通过接受或返回通道、回调函数来体现。理解这一模式有助于避免冗余的goroutine启动,并确保正确管理并发。 理解…

    2025年12月16日
    000
  • Golang如何实现worker pool模式

    Go语言中通过goroutine和channel实现Worker Pool,核心是固定数量的worker从任务队列中取任务执行。1. 基本结构包括任务、任务channel、worker协程和sync.WaitGroup等待机制。2. 示例代码启动3个worker处理5个job,使用有缓存channe…

    2025年12月16日
    000
  • Go语言中创建Map:{}字面量与make()函数的异同与选择

    本文深入探讨go语言中两种创建map的方式:`map[keytype]valuetype{}`字面量与`make(map[keytype]valuetype)`函数。我们将详细分析它们在初始化、容量指定以及性能方面的异同,并提供选择指南,帮助开发者根据实际需求高效创建和管理map。 在Go语言中,M…

    2025年12月16日
    000
  • Golang如何使用pprof分析内存泄漏

    答案是使用Go的pprof工具通过采集堆内存快照分析内存泄漏,具体步骤为导入net/http/pprof包并启动HTTP服务,访问/debug/pprof/heap获取实时堆信息,结合go tool pprof进行可视化分析,重点关注inuse_space和inuse_objects指标,通过对比多…

    2025年12月16日
    000
  • Go语言中如何判断两个切片是否引用同一内存起始地址

    本教程将深入探讨在go语言中如何准确判断两个切片是否引用了相同的内存起始地址。go切片作为对底层数组的视图,可能共享同一块内存。我们将介绍使用`reflect`包中的`valueof().pointer()`方法来获取切片数据在内存中的起始地址,并通过比较这些地址来确定它们是否指向完全相同的数据起点…

    2025年12月16日
    000
  • Go语言Map键的比较性要求与潜在编译器行为分析

    本文深入探讨go语言中map键的类型限制,特别是结构体中包含切片字段时作为键的问题。根据go语言规范,map键必须是可比较类型,而切片、函数和map本身不可比较,这一限制会传递到包含它们的结构体。文章通过示例代码分析了编译器行为,并解释了为何某些情况下看似矛盾的编译结果可能源于编译器优化或特定场景下…

    2025年12月16日
    000
  • Go语言中CSV数据导入MS SQL的健壮性实践:解决记录丢失问题

    本文深入探讨了go语言使用`go-odbc`将csv数据导入ms sql时,部分记录可能随机丢失的问题。通过分析`fmt.printf()`意外解决此现象的背后原因,我们揭示了eof处理不当、数据库操作错误检查不足以及资源管理缺陷等核心问题。文章提供了一套健壮的数据导入方案,包括优化的eof判断、严…

    2025年12月16日
    000
  • 创建指定大小并填充特定数据的Golang文件教程

    本文将介绍如何使用Golang创建一个指定大小的文件,并用特定数据填充它。我们将使用 `os` 包提供的函数来创建和截断文件,从而实现快速生成大文件的目的。示例代码展示了如何创建一个10MB的文件,并将其填充为全零数据。掌握这些方法,可以方便地在例如日志系统或磁盘队列等场景中,预先创建测试文件或初始…

    2025年12月16日
    000
  • 如何在Golang中实现错误日志记录

    使用标准库log和结构化日志库zap记录错误,结合errors包增强堆栈信息,并通过中间件统一处理HTTP服务错误,确保日志清晰可追溯。 在Golang中实现错误日志记录,关键在于结合标准库和结构化日志工具,确保错误信息清晰、可追溯。Go的error类型简单但功能有限,因此需要配合日志系统来记录上下…

    2025年12月16日
    000
  • Go语言文件系统抽象与模拟实践

    本文探讨了在go语言中通过接口实现文件系统抽象的方法,旨在提升应用的可测试性、可观测性及灵活性。通过定义 `filesystem` 和 `file` 接口,我们可以轻松地替换底层文件操作,实现如文件读写日志记录、内存文件系统模拟等高级功能,从而避免直接依赖 `os` 包,使代码更易于维护和扩展。 在…

    2025年12月16日
    000
  • Go 命令解析:go run 与 go build 的差异及应用场景

    本文深入探讨了 go 语言中 `go run` 和 `go build` 命令的核心差异及其工作原理。`go run` 编译至临时目录并执行,影响 `os.args[0]` 和工作目录,适用于开发调试;而 `go build` 生成独立二进制文件,通常在当前目录执行,适用于生产部署。理解这些差异对于…

    2025年12月16日
    000
  • Go语言Web应用开发:App Engine、自托管与框架选型深度解析

    go语言在web开发中因其简洁高效备受青睐。本文旨在探讨go应用部署的两种主要策略:利用google app engine (gae) 等云平台,或选择自托管服务器;同时,还将深入分析使用go标准库`net/http`与各类web框架的优劣,帮助开发者根据项目需求做出明智的技术选型,从而构建高效、可…

    2025年12月16日
    000
  • Golang JSON解析错误如何处理

    正确处理Golang JSON解析错误需检查error并区分类型。常见错误有格式错误、类型不匹配、字段缺失和嵌套结构不一致。使用json.Unmarshal时应判断返回的error,可通过类型断言识别json.SyntaxError、json.UnmarshalTypeError等,进而精细化处理。…

    2025年12月16日
    000
  • Go语言中与交互式命令行程序进行程序化交互的正确姿势

    在go语言中,程序化地向外部命令行工具提供输入,特别是应对交互式提示(如ssh连接时的确认),是一个常见需求。本文将深入探讨直接模拟用户输入的方法为何不可取,并指出其潜在风险。我们将重点介绍如何利用go的专用库(如`golang.org/x/crypto/ssh`)进行协议级交互,这才是处理复杂协议…

    2025年12月16日
    000
  • Golang如何使用指针修改函数外变量

    Go语言中函数参数为值传递,需通过指针修改外部变量;使用&取地址,*解引用,传入变量地址后在函数内操作指针可改变原值,如increment函数使num变为6;结构体同理,updatePerson函数将person改为{Alice 30},同时避免大对象复制提升性能。 在Go语言中,函数参数是…

    2025年12月16日
    000

发表回复

登录后才能评论
关注微信