iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >基于 Hyperf ,进行便捷的上下文和协程调度管理,实现 伪事务 般的defer应用和请求级上下文管理
  • 601
分享到

基于 Hyperf ,进行便捷的上下文和协程调度管理,实现 伪事务 般的defer应用和请求级上下文管理

数据库phpswoole 2023-10-09 13:10:38 601人浏览 薄情痞子
摘要

hyperf Hyperf Go Coroutine defer 场景 一个api项目,日常写代码过程中,在需要进行上下文设置时,当然是字面意思,但有时候,一个API动作的完成,可能需要有一些主

hyperf Hyperf Go Coroutine defer

场景

一个api项目,日常写代码过程中,在需要进行上下文设置时,当然是字面意思,但有时候,一个API动作的完成,可能需要有一些主动发起的协程调度,如 CSP 之类,或者 第三方耗时API 需要在事务最后进行,这些实践起来,虽然原生方法能够解决,但并不优雅,我对其进行了一定的改造,以实现:

  • Db事务中,将第三方耗时API请求、MQ投递 放在 EasyCo::defer 里,在Db事务结束时,commit就正常commit,但 rollBack 时,可以通过 EasyCo::deferRollBack 取消本次动作中注册的defer
  • 在一次 API动作 实现的过程中,通过 EasyCtx::set 设定的上下文变量,可以在本次请求里,通过任何 EasyCo::create 创建的协程里,EasyCtx::get 拿到,不需要进行主动的协程use和赋值

应用Demo

defer 的伪事务

//伪代码Db::beginTransaction();try {//TODO 业务操作make(UserService::class)->bsAction();//耗时操作// - 第三方API 联动业务// - 投递MQEasyCoroutine::easyDeferTrans(function (){//你的耗时操作});Db::commit();}catch (\Throwable $exception){Db::rollBack();EasyCoroutine::easyDeferRollBack();}        

通过这样的姿势,在一些你本来就封装了事务操作A,被嵌套在别人的复合事务操作B时,你的A就不是最终执行事务了,PHP本身没有嵌套事务,这样的嵌套只会合并为一个大事务进行执行,只需要在任意的 Db::rollBack() 时,同步执行 EasyCoroutine::easyDeferRollBack() ,即可取消掉本次注册的defer

请求级上下文

EasyContext::easySet('testData',1123123);        EasyCoroutine::easyCreate(function (){EasyContext::easyGet('testData');});

通过这样的姿势,只要是 EasyCtx::set 的变量,必定可在 EasyCo::create 创建的协程中,通过 EasyCtx::get 进行获取,即可完成请求级的上下文管理,并且只是赋值,无地址干扰操作


源码

EasyCtx

phpdeclare (strict_types=1);namespace App\Utils;use Hyperf\Context\Context;use Hyperf\Utils\Str;use Hyperf\websocketServer\Context as WsContext;class EasyContext{        public static function __callStatic($name, $arguments)    {        if (Str::startsWith(strtolower($name), 'ws')) {            //非ws环境中,使用ws上下文会导致内存泄漏,请谨慎使用            $wsMethodMap = [                'wsSet'          => 'set',                'wsGet'          => 'get',                'wsHas'          => 'has',                'wsDestroy'      => 'destroy',                'wsRelease'      => 'release',                'wsCopy'         => 'copy',                'wsOverride'     => 'override',                'wsGetOrSet'     => 'getOrSet',                'wsGetContainer' => 'getContainer',            ];            $method      = $wsMethodMap[$name] ?? false;            return WsContext::{$method}(...$arguments);        }        return Context::{$name}(...$arguments);    }        public static function easySet(mixed $id, mixed $value): mixed    {        $key          = self::ctxKey();        $current      = Context::getOrSet($key, []);        $current[$id] = $value;        return Context::set($key, $current);    }        public static function easyGet(string $id, $default = null): mixed    {        $current = Context::get(self::ctxKey(), []);        if (!$current) {            return $default;        } else {            return $current[$id] ?? $default;        }    }    static private function ctxKey(): string    {        return 'EasyContextCreate';    }}

defer 伪事务

declare (strict_types=1);namespace App\Utils;use Hyperf\Context\Context;use Hyperf\Utils\Coroutine;class EasyCoroutine{        public static function __callStatic($name, $arguments)    {        return Coroutine::{$name}(...$arguments);    }        static public function easyCreate(callable $callable): int    {        //创建时,获取当前特定需传输的上下文        $current = Context::get(self::ctxKey(), []);        return Coroutine::create(function () use ($callable, $current) {            try {                //也许copy进来,但感觉没必要,copy会直接覆盖且清空原上下文                //此处进行强行覆盖操作 其实等同于copy                Context::set(self::ctxKey(), $current);                call($callable);            } catch (\Throwable $exception) {                //日志记录                //通过 opis/closure 可将回调函数作为字符串保存日志 \Opis\Closure\serialize($callable)            }        });    }        static public function easyDeferTrans(callable $callable): string    {        if (Coroutine::inCoroutine()) {            $id = Coroutine::id() . '-' . session_create_id();        } else {            $id = uniqid() . '-' . session_create_id();        }        $deferCtx      = Context::getOrSet(self::deferCtxKey(), []);        $deferCtx[$id] = 1;        Context::set(self::deferCtxKey(), $deferCtx);        $fn = function () use ($callable, $id) {            try {                $deferCtx = Context::get(self::deferCtxKey(), []);                $defer = intval($deferCtx[$id] ?? 0);                if ($defer) {                    call($callable);                }            } catch (\Throwable $exception) {                //日志记录                //通过 opis/closure 可将回调函数作为字符串保存日志 \Opis\Closure\serialize($callable)            }        };        Coroutine::defer($fn);        return $id;    }        static public function easyDeferRollBack(): void    {        try {            if (Coroutine::inCoroutine()) {                Context::set(self::deferCtxKey(), []);            } else {                Context::destroy(self::deferCtxKey());            }        } catch (\Throwable $exception) {            //日志记录            //通过 opis/closure 可将回调函数作为字符串保存日志 \Opis\Closure\serialize($callable)        }    }        static public function easyDeferRollBackById(mixed $id): void    {        try {            $deferCtx = Context::get(self::deferCtxKey(), []);            if ($deferCtx) {                $deferCtx[$id] = 0;                Context::set(self::deferCtxKey(), $deferCtx);            }        } catch (\Throwable $exception) {            //日志记录            //通过 opis/closure 可将回调函数作为字符串保存日志 \Opis\Closure\serialize($callable)        }    }        static private function deferCtxKey(): string    {        return 'EasyCoroutineDefer';    }        static private function ctxKey(): string    {        return 'EasyContextCreate';    }}

来源地址:https://blog.csdn.net/liyunfan2016/article/details/128077937

--结束END--

本文标题: 基于 Hyperf ,进行便捷的上下文和协程调度管理,实现 伪事务 般的defer应用和请求级上下文管理

本文链接: https://www.lsjlt.com/news/426293.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作