Laravel Octane 和 Swoole 协程的使用分析

之前在工作中使用 Laravel Octane 的 concurrently 处理并发时,发现在队列和定时任务中不会触发并发效果。经过分析,作了如下猜测:队列和定时任务都属于一个独立的进程,与 Octane 服务无关,而 Octane concurrently 恰恰需要在 Octane 环境下才能运行。

后来通过代码进行环境检测和查看 php 的进程,证明猜想成立。

info('check env', [
    'served by octane' => isset($_SERVER['LARAVEL_OCTANE']) && ((int)$_SERVER['LARAVEL_OCTANE'] === 1),
    'on swoole server' => (extension_loaded('swoole') || extension_loaded('openswoole')) && app()->bound(Server::class)
]);

为了能够在任意代码中实现并发,我们研究参考了 Hyperf 框架关于协程的代码,然后抽取了如下两个类:

<?php

namespace App\Services;

use App\Exceptions\ParallelExecutionException;
use Laravel\Octane\Facades\Octane;
use Throwable;
use Swoole\Coroutine as Co;

class Parallel
{
    protected array $callbacks = [];
    protected array $results = [];
    /**
     * @var Throwable[]
     */
    protected array $throwables = [];

    public function add(callable $callable, $key = null): void
    {
        if (is_null($key)) {
            $this->callbacks[] = $callable;
        } else {
            $this->callbacks[$key] = $callable;
        }
    }

    public function wait(bool $throw = true): array
    {
        if (isset($_SERVER['LARAVEL_OCTANE']) && ((int)$_SERVER['LARAVEL_OCTANE'] === 1)) {
            return Octane::concurrently($this->callbacks, 300000);
        }

        app('log')->useLoggingLoopDetection(false);
        
        Co\run(function () {
            foreach ($this->callbacks as $key => $callback) {
                Co::create(function () use ($callback, $key) {
                    try {
                        $this->results[$key] = $callback();
                    } catch (Throwable $throwable) {
                        $this->throwables[$key] = $throwable;
                        unset($this->results[$key]);
                    }
                });

            }
        });

        if ($throw && ($throwableCount = count($this->throwables)) > 0) {
            $message = 'Detecting ' . $throwableCount . ' throwable occurred during parallel execution:' . PHP_EOL . $this->formatThrowAbles($this->throwables);
            $executionException = new ParallelExecutionException($message);
            $executionException->setResults($this->results);
            $executionException->setThrowAbles($this->throwables);
            unset($this->results, $this->throwables);
            throw $executionException;
        }

        app('log')->useLoggingLoopDetection(true);
        return $this->results;
    }

    private function formatThrowAbles(array $throwables): string
    {
        $output = '';
        foreach ($throwables as $key => $value) {
            $output .= sprintf('(%s) %s: %s' . PHP_EOL . '%s' . PHP_EOL, $key, get_class($value), $value->getMessage(), $value->getTraceAsString());
        }
        return $output;
    }
}
<?php

namespace App\Exceptions;

use RuntimeException;

class ParallelExecutionException extends RuntimeException
{
    protected array $results = [];

    protected array $throwables = [];

    public function getResults(): array
    {
        return $this->results;
    }

    public function setResults(array $results): void
    {
        $this->results = $results;
    }

    public function getThrowAbles(): array
    {
        return $this->throwables;
    }

    public function setThrowAbles(array $throwables): array
    {
        return $this->throwables = $throwables;
    }
}

其中,第一个类的作用是检测系统是否运行在 Octane 环境下,是则调用Octane concurrently,否则就执行 Swoole 协程代码,使用起来也比较简单:

$parallel = new Parallel();
$parallel->add(fn() => $this->analysisStructure(), 'structure');
$parallel->add(fn() => $this->analysisHabit(), 'habit');
[
    'structure' => $structure,
    'habit' => $habit,
] = $parallel->wait();

之所以没有完全使用 Swoole 协程,是因为相比之下,Octane 代码更加优雅,我们在期待着某天更新后,Octane concurrently 也能直接在队列中运行使用。

第二个类的作用比较简单,就是对协程中异常的一个定义。

另外在分析过程中,我们也发现了一个比较有意思的事情:
在这里插入图片描述

如图所示,当我在路由中运行检测代码时,Octane 和 Swoole Server 都为 true;在控制器中运行检测代码时,又只有 Octane 为true;为什么会有这样的区分?我个人猜测是 Octane 在将框架代码读进内存时,特意跳过了控制器中的代码,以避免数据更新不及时等问题。

有知道具体原因的小伙伴,欢迎留言探讨。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/422117.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

msvcr120.dll丢失的解决办法,分享解决文件丢失的问题

msvcr120.dll文件丢失有这三种方法可以解决&#xff0c;学会这三种方法的任何一种&#xff0c;以后再出现dll文件丢失的情况都能很好地解决&#xff0c;第一种方法最为简单。先给大家说说msvcr120.dll文件为什么会丢失&#xff1f;丢失的原因是什么&#xff1f; 一.msvcr120.d…

win10安全中心误删文件怎么办?解析恢复与预防策略

在使用Windows 10的过程中&#xff0c;许多用户依赖于其内置的安全中心来保护电脑免受恶意软件的侵害。然而&#xff0c;有时安全中心的误判可能导致重要文件被错误地删除。当面对这种情况时&#xff0c;了解如何恢复误删的文件并掌握预防措施显得尤为重要。本文将为您详细解析…

redis01 基本概念初识

SQL与NOSQL对比 Redis介绍 诞生于2009年&#xff0c;全称是Remote Dictionary Server&#xff0c;远程词典服务器&#xff0c;是一个基于内存的键值型NOSQL数据库。 Redis基本概念 redis为什么快 基于内存&#xff08;核心&#xff09;&#xff0c;IO多路复用&#xff0c;良…

二百二十五、海豚调度器——用DolphinScheduler调度执行Flume数据采集任务

一、目的 数仓的数据源是Kafka&#xff0c;因此离线数仓需要用Flume采集Kafka中的数据到HDFS中 在实际项目中&#xff0c;不可能一直在Xshell中启动Flume任务&#xff0c;一是项目的Flume任务很多&#xff0c;二是一旦Xshell页面关闭Flume任务就会停止&#xff0c;这样非常不…

if-else 语句

if-else 语句 概念&#xff1a;是双条件分支语句&#xff0c;根据一个条件来控制程 序执行的流程。 语法格式&#xff1a; if&#xff08;表达式&#xff09; { 若干语句 } else { 若干语句 }

GEE必须会教程—蒸散发数据时间序列分析与下载

今天带来的有关蒸散发数据的下载代码&#xff0c;蒸散发数据在气象气候&#xff0c;农业干旱监测等领域应用广泛&#xff0c;那么在GEE上如何方便快捷获取蒸散发数据呢&#xff1f;今天跟着小编分享代码&#xff0c;快来学习吧&#xff01;&#xff01; A.定义研究区域 //定义…

【C++】类型转换和IO流

目录 C语言中的类型转换 C eplicit && volatitle eplicit volatile C强制类型转换 static_cast(相关类型) reinterpret_cast(不相关类型&#xff09; const_cast&#xff08;去掉const属性&#xff09; dynamic_cast RTTI&#xff08;了解&#xff09; IO流 …

ChatGpt 使用fetch-event-source实现sse流式处理

microsoft/fetch-event-source 是一个由微软提供的库&#xff0c;用于在客户端和服务器之间建立基于 EventSource 的连接。EventSource 是一种 HTTP 协议&#xff0c;允许服务器向客户端推送实时事件流。该库提供了对 EventSource 协议的封装&#xff0c;使得在前端 JavaScript…

二维码门楼牌管理系统技术服务:革新城市标识管理的新篇章

文章目录 前言一、二维码门楼牌管理系统的诞生背景二、二维码门楼牌管理系统的技术优势三、二维码门楼牌管理系统的应用前景四、面临的挑战与问题五、结语 前言 在数字化、智能化的时代背景下&#xff0c;二维码门楼牌管理系统作为一种创新的技术服务&#xff0c;正逐渐改变着…

AIGC下一步:如何用AI再度重构或优化媒体处理?

让媒资中“沉默的大多数”再次焕发光彩。 邹娟&#xff5c;演讲者 编者按 AIGC时代下&#xff0c;媒体内容生产领域随着AI的出现也涌现出更多的变化与挑战。面对AI的巨大冲击&#xff0c;如何优化或重构媒体内容生产技术架构&#xff1f;在多样的应用场景中媒体内容生产技术又…

springboot基于web的酒店客房管理系统论文

基于web的酒店客房管理系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了酒店客房管理系统的开发全过程。通过分析酒店客房管理系统管理的不足&#xff0c;创建了一个计算机管理酒店客房管理系统的方案。文…

锐捷网络携数据中心、以太全光等创新解决方案亮相2024MWC

在西班牙巴塞罗那举行的2024年世界移动通信大会(MWC)上,锐捷网络(下文简称“锐捷”)展示了将技术与应用充分融合的云数据中心、5G、光网络等产品及解决方案,帮助更多行业组织建设更贴近业务、智能、简单、高效、绿色低碳的网络基础设施,应对当下及未来的挑战,共同连接更广阔可能…

ceph性能测试

查看集群状态 ceph -s查看osd情况 ceph osd tree创建pg_num为60的pool&#xff0c;名为test。 ceph osd pool create test 60rados bench用于测试rados存储池底层性能&#xff0c;该工具可以测试写、顺序读、随机读三种类型 rados bench -p <pool_name> <seconds&…

[物联网] OneNet 多协议TCP透传

[物联网] OneNet 多协议TCP透传 STM32物联网–ONENET云平台的多协议接入产品创建 : https://blog.csdn.net/qq_44942724/article/details/134492924 Onenet tcp 透传 : https://blog.csdn.net/flyme2010/article/details/107086001 tcp服务端测试工具 : http://tcp.xnkiot.com/…

Day12-【Java SE进阶】JDK8新特性:Lambda表达式、方法引用、常见算法、正则表达式、异常

一、JDK8新特性 1.Lambda表达式 Lambda表达式是JDK 8开始新增的一种语法形式;作用:用于简化名内部类的代码写法。 注意:Lambda表达式并不是说能简化全部匿名内部类的写法&#xff0c;只能简化函数式接口的匿名内部类。 有且仅有一个抽象方法的接口。注意:将来我们见到的大部…

IntelliJ IDEA 2023 点击推送至远程仓库发生报错

开始我是直接在IDEA里创建的本地仓库&#xff0c;然后在gitee上的仓库是创建并初始化的&#xff0c;因为你点击初始化后&#xff0c;会默认帮你执行一些代码&#xff0c;然后你再在本地仓库推送至远程仓库就会出现不一致的情况。 当你本地的仓库与远程仓库中的内容不同步时&…

echarts vue 动画效果的水球图、波浪图教程

1、安装插件 前提是已经安装了echarts&#xff08;我的版本是4.2.1&#xff09; npm install echarts-liquidfill --save 我安装了3.1.0版本的&#xff0c;结果运行时报错"TypeError: wave.ensureState is not a function" 原因&#xff1a;echarts版本和echarts-l…

基于JAVA的聊天(ICQ)系统的设计于实现

一、绪论 ICQ是英文"I seek you "的简称&#xff0c;中文意思是我找你。ICQ最大的功能就是即时信息交流&#xff0c;只要记得对方的号码&#xff0c;上网时可以呼他&#xff0c;无论他在哪里&#xff0c;只要他上网打开ICQ&#xff0c;人们就可以随时交流。ICQ源于以…

GenAI助力DevOps,塑造软件工程的未来

自 2022 年以来&#xff0c;GenAI 无疑已成为一种普遍的技术趋势。在本文中&#xff0c;我们将探索 DevOps 中令人兴奋的 GenAI 领域&#xff0c;讨论其潜在优势、局限性、新兴趋势和最佳实践&#xff0c;深入了解 AI 支持的 DevOps 前沿世界&#xff0c;并探索这一强大组合如何…

Redis的主从搭建

1.准备两台机器&#xff0c;安装好redis 2.修改从服务器的redis配置 slaveof <masterip> <masterport>两个参数 masterip 主的ip 主的端口号 masterport 3. 启动redis 1.先启动主机redis 2.再启用从机redis 主机redis日志打印 从机redis 日志打印