{"id":33991239,"url":"https://github.com/njutsiang/async-helper","last_synced_at":"2026-03-11T01:02:20.537Z","repository":{"id":57010431,"uuid":"119834033","full_name":"njutsiang/async-helper","owner":"njutsiang","description":"PHP 的异步进程助手，借助于 AMQP 实现异步执行 PHP 的方法","archived":false,"fork":false,"pushed_at":"2018-03-31T18:26:26.000Z","size":13,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-14T18:50:18.745Z","etag":null,"topics":["amqp","async","php"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/njutsiang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-01T12:39:33.000Z","updated_at":"2021-12-24T02:27:51.000Z","dependencies_parsed_at":"2022-08-21T15:10:20.897Z","dependency_job_id":null,"html_url":"https://github.com/njutsiang/async-helper","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/njutsiang/async-helper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/njutsiang%2Fasync-helper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/njutsiang%2Fasync-helper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/njutsiang%2Fasync-helper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/njutsiang%2Fasync-helper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/njutsiang","download_url":"https://codeload.github.com/njutsiang/async-helper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/njutsiang%2Fasync-helper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30364608,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"ssl_error","status_checked_at":"2026-03-10T21:40:59.357Z","response_time":106,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amqp","async","php"],"created_at":"2025-12-13T06:41:31.375Z","updated_at":"2026-03-11T01:02:20.484Z","avatar_url":"https://github.com/njutsiang.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# async-helper\n\n## 简介\nPHP 的异步进程助手，借助于 AMQP 实现异步执行 PHP 的方法，将一些很耗时、追求高可用、需要重试机制的操作放到异步进程中去执行，将你的 HTTP 服务从繁重的业务逻辑中解脱出来。以一个较低的成本将传统 PHP 业务逻辑转换成非阻塞、高可用、可扩展的异步模式。\n\n## 依赖\n- php 5.6+\n- ext-bcmath\n- ext-amqp 1.9.1+\n- ext-memcached 3.0.3+\n\n## 安装\n通过 composer 安装\n```\ncomposer require l669/async-helper\n```\n或直接下载项目源码\n```\nwget https://github.com/l669306630/async-helper/archive/master.zip\n```\n\n## 使用范例\n**业务逻辑**：这里定义了很多等待被调用的类和方法，在你的项目中这可能是数据模型、或是一个发送邮件的类。\n```php\n\u003c?php\nclass SendMailHelper \n{\n    /**\n     * @param array $mail\n     * @throws Exception\n     */\n    public static function request($mail)\n    {\n        // 在这里发送邮件，或是通过调用第三方提供的服务发送邮件\n        // 发送失败的时候你抛出了异常，希望被进程捕获，并按设定的规则进行重试\n    }\t\n}\n```\n\n**生产者**：通常是 HTTP 服务，传统的 PHP 项目或是一个命令行程序，接收到某个请求或指令后进行一系列的操作。\n```php\n\u003c?php \nuse l669\\AsyncHelper;\nclass UserController\n{\n    public function register()\n    {\n        // 假设这是一个用户注册的请求，用户提交了姓名、邮箱、验证码\n        // 第一步、校验用户信息\n        // 第二步、实例化异步助手，这时候会连接 AMQP\n        $async_helper = new AsyncHelper([\n            'host' =\u003e '127.0.0.1',\n            'port' =\u003e '5672',\n            'user' =\u003e 'root',\n            'pass' =\u003e '123456',\n            'vhost' =\u003e '/'\n        ]);\n        // 第三步、保存用户信息到数据库\n        $mail = [\n            'from' =\u003e 'service@yourdomain.com', \n            'to' =\u003e 'username@163.com', \n            'subject' =\u003e '恭喜你注册成功',\n            'body' =\u003e '请点击邮件中的链接完成验证....'\n        ];\n        // 第四步、通过异步助手发送邮件\n        $async_helper-\u003erun('\\\\SendMailHelper', 'request', [$mail]);\n        \n        // 这是同步的模式去发送邮件，如果邮件服务响应迟缓或异常，就会直接影响该请求的响应时间，甚至丢失这封重要邮件\n        // SendMailHelper::request($mail);\n    }\n}\n```\n\n**消费者**：PHP 的异步进程，监听消息队列，执行你指定的方法。并且该消费者进程是可扩展的高可用的服务，这一切都得益于 AMQP，这是系统解耦、布局微服务的最佳方案。\n\nconsume.php\n```php\n\u003c?php\nrequire_once('vendor/autoload.php');\nrequire_once('SendMailHelper.php');\n\nuse l669\\AsyncHelper;\nuse l669\\CacheHelper;\n\n$cache_helper = new CacheHelper('127.0.0.1', 11211);\nwhile(true){\n    try{\n        $async_helper = new AsyncHelper([\n            'host' =\u003e '127.0.0.1',\n            'port' =\u003e '5672',\n            'user' =\u003e 'root',\n            'pass' =\u003e '123456',\n            'vhost' =\u003e '/',\n            'cacheHelper' =\u003e $cache_helper\n        ]);\n        $async_helper-\u003econsume();\n    }catch(Exception $e){\n        // 可以在这里记录一些日志\n        sleep(2);\n    }\n}\n```\n```\n# 在命令行下启动消费者进程，推荐使用 supervisor 来管理进程\nphp consume.php\n```\n\n**支持事务**：需要一次提交执行多个异步方法，事务可以确保完成性。\n```php\n// 接着上面的示例来说，这里省略了一些重复的代码，下同\n$async_helper-\u003ebeginTransaction();\ntry{\n    $async_helper-\u003erun('\\\\SendMailHelper', 'request', [$mail1]);\n    $async_helper-\u003erun('\\\\SendMailHelper', 'request', [$mail2]);\n    $async_helper-\u003erun('\\\\SendMailHelper', 'request', [$mail3]);\n    $async_helper-\u003ecommit();\n}catch(\\Exception $e){\n    $async_helper-\u003erollback();\n}\n```\n\n**阻塞式重试**：当异步进程执行一个方法，方法内部抛出异常时进行重试，一些必须遵循执行顺序的业务就要采用阻塞式的重试，通过指定重试最大阻塞时长来控制。\n```php\nuse l669\\CacheHelper;\nuse l669\\AsyncHelper;\n$async_helper = new AsyncHelper([\n    'host' =\u003e '127.0.0.1',\n    'port' =\u003e '5672',\n    'user' =\u003e 'root',\n    'pass' =\u003e '123456',\n    'vhost' =\u003e '/',\n    'cacheHelper' =\u003e new CacheHelper('127.0.0.1', 11211),\n    'retryMode' =\u003e AsyncHelper::RETRY_MODE_REJECT,  // 阻塞式重试\n    'maxDuration' =\u003e 600                            // 最长重试 10 分钟\n]);\n$send_mail_helper = new \\SendMailHelper();\n$mail = new \\stdClass();\n$mail-\u003efrom = 'service@yourdomain.com';\n$mail-\u003eto = 'username@163.com';\n$mail-\u003esubject = '恭喜你注册成功';\n$mail-\u003ebody = '请点击邮件中的链接完成验证....';\n$async_helper-\u003erun($send_mail_helper, 'request', [$mail]);\n\n// 如果方法中需要抛出异常来结束程序，又不希望被异步进程重试，可以抛出以下几种错误码，进程捕获到这些异常后会放弃重试：\n// l669\\AsyncException::PARAMS_ERROR\n// l669\\AsyncException::METHOD_DOES_NOT_EXIST\n// l669\\AsyncException::KNOWN_ERROR\n```\n\n**非阻塞式重试**：当异步执行的方法内部抛出异常，async-helper 会将该方法重新放进队列的尾部，先执行新进入队列的方法，回头再重试刚才执行失败的方法，通过指定最大重试次数来控制。\n```php\nuse l669\\CacheHelper;\nuse l669\\AsyncHelper;\n$async_helper = new AsyncHelper([\n    'host' =\u003e '127.0.0.1',\n    'port' =\u003e '5672',\n    'user' =\u003e 'root',\n    'pass' =\u003e '123456',\n    'vhost' =\u003e 'new',\n    'cacheHelper' =\u003e new CacheHelper('127.0.0.1', 11211),\n    'queueName' =\u003e 'emails.vip',                    // 给付费的大爷走 VIP 队列\n    'retryMode' =\u003e AsyncHelper::RETRY_MODE_TTL,     // 非阻塞式重试\n    'maxRetries' =\u003e 10                              // 最多重试 10 次\n]);\n$mail = new \\stdClass();\n$mail-\u003efrom = 'service@yourdomain.com';\n$mail-\u003eto = 'username@163.com';\n$mail-\u003esubject = '恭喜你注册成功';\n$mail-\u003ebody = '请点击邮件中的链接完成验证....';\n$async_helper-\u003erun('\\\\SendMailHelper', 'request', [$mail]);\n```\n\n## 应用和解惑\n* 我们采用的是开源的 RabbitMQ 来为我们提供的 AMQP 服务。\n* 你的项目部署在拥有很多服务器节点的集群上，每个节点的程序都需要写日志文件，现在的问题就是要收集所有节点上面的日志到一个地方，方便我们及时发现问题或是做一些统计。所有节点都可以使用 async-helper 异步调用一个写日志的方法，而执行这个写日志的方法的进程只需要在一台机器上启动就可以了，这样所有节点的日志就都实时掌握在手里了。\n* 做过微信公众号开发的都知道，腾讯微信可以将用户的消息推送到我们的服务器，如果我们在 5s 内未及时响应，腾讯微信会重试 3 次，其实这就是消息队列的应用，使用 async-helper 可以轻松的做和这一样的事情。\n* 得益于 RabbitMQ，你可以轻松的横向扩展你的消费者进程的能力，因为 RabbitMQ 天生就支持集群部署，你可以轻松的启动多个消费者进程，或是将消费者进程分布到多台机器上。\n* 如果 RabbitMQ 服务不可用怎么办呢？部署 RabbitMQ 高可用服务是容易的，对外提供单一 IP，这个 IP 是个负载均衡，背后是 RabbitMQ 集群，负载均衡承担对后端集群节点的健康检查。\n* async-helper 能否承受高并发请求？async-helper 生产者使用的是短连接，也就说在你的 HTTP 还没有响应浏览器的时候 async-helper 就已经结束了工作，你连接 RabbitMQ 的时间是百分之百小于 HTTP 请求的时间的，换言之，只要 RabbitMQ 承受并发的能力超过你的 HTTP 服务的承受并发的能力，RabbitMQ 就永远不会崩，通过横向扩展 RabbitMQ 很容易做到的。\n\n## 和传统 PHP 相比\n* 对任何 PHP 方法通过反射进行异步执行；\n* 高可用，执行方法进入消息队列，可持久化，即使服务器宕机，执行任务也不丢失；\n* 高可用，对异常可以进行不限次数和时间的重试，重试次数和时间可配置；\n* 支持对多个异步方法包含在事务中执行，支持回滚事务；\n* 方法的参数类型支持除资源类型（resource）和回调函数（callable）外的任意类型的参数；\n* 得益于 AMQP，异步方法可以承受高并发、高负载，支持集群部署、横向扩展；\n* 低延时，实测延时时间 0.016 ～ 0.021s；\n* 适用于：日常数据库操作、日志收集、金融交易、消息推送、发送邮件和短信、数据导入导出、计算大量数据生成报表；\n\n## 附录\n- [安装 memcached](https://segmentfault.com/n/1330000012854656)\n- [安装 rabbitmq](https://segmentfault.com/n/1330000012865854?token=98d34e1eac9cac279d84abba0c45f834)\n- [安装 php7.1.5、ext-amqp、ext-memcached](https://segmentfault.com/n/1330000012854879?token=4a1e0e0debb594ba20d091e6a7fa40d2)\n- [安装 supervisor](https://segmentfault.com/n/1330000012996856?token=08f6ca7a324368d6b17efef67ccdaa64)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnjutsiang%2Fasync-helper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnjutsiang%2Fasync-helper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnjutsiang%2Fasync-helper/lists"}