# 开发必看

ModStart 基于原生 Laravel 开发,独创了方便易扩展的模块开发架构,通过配置式的开发过程,可以快速实现系统搭建。

# 开发流程

强烈推荐如下的开发流程开展系统开发工作:

  1. 本地安装 ModStart 框架,搭建开发环境;
  2. 在开发环境安装模块,同时进行二次开发和测试;
  3. 使用代码管理工具同步代码到仓库( git (opens new window)svn (opens new window));
  4. 使用代码仓库的代码部署到生产服务器。

# 代码结构

系统代码结构参照 Laravel 的目录结构,开发前必须了解以下目录

目录 介绍
app/ 应用代码目录,包含了应用的主要业务代码
config/ 包含了应用所有的配置文件,建议通读一遍这些配置文件以便熟悉 Laravel 所有默认配置项
database/ 包含了数据库迁移文件及填充文件
module/ 模块代码目录,每个模块一个目录
public/ 目录包含了应用入口文件 index.php 和前端资源文件(图片、JavaScript、CSS等
public/data/ 上传的图片、文件、视频等静态资源会存储在该目录
public/vendor/ 模块静态资源目录
vendor/modstart/modstart ModStart核心架构目录
resources/ 包含了应用视图文件、本地化语言文件
storage/ 包含了编译后的 Blade 模板、基于文件的 Session、文件缓存、日志文件等。

# 应用、模块、功能组

  • 模块:有比较独立的功能,代码在 module/ 目录,每个模块一个目录,模块市场安装的模块也在该目录中。
  • 应用:和业务相关的代码不能独立成为模块复用,代码在 app/ 目录,用于系统个性化的需求开发。
  • 功能组:位于模块目录中,常见的功能组有 WebApiAdminOpenApi ,分别提供不同的分组功能

模块最基本要求是可复用,可以是一个完整行业应用,可以纯技术框架SDK,也可以是一个可拆卸和安装的功能插件,模块的定义要经过深思熟虑,避免模块的滥用。

规划开发好的模块,可以发布到模块市场上供大家付费/免费使用,共享技术成果。

开发时请按照约定的功能组

# 路由加载流程

通过 ModStart\ModStartServiceProvider 类来管理,具体的加载过程参考相关实现逻辑。

# Web 功能组

系统会按照如下的顺序加载路由文件。

  • module/Xxx/Web/routes.php:所有模块中的Web前台路由
  • app/Web/routes.php:系统应用Web前台路由

# Admin 功能组

系统会按照如下的顺序加载路由文件。

  • module/Xxx/Admin/routes.php:所有模块中的Admin后台路由
  • app/Admin/routes.php:系统应用Admin后台路由

# Api 功能组

系统会按照如下的顺序加载路由文件。

  • module/Xxx/Api/routes.php:所有模块中的Api接口路由
  • app/Api/routes.php:系统应用Api接口路由

# OpenApi 功能组

系统会按照如下的顺序加载路由文件。

  • module/Xxx/OpenApi/routes.php:所有模块中的OpenApi开放接口路由
  • app/OpenApi/routes.php:系统应用OpenApi开放接口路由

# Composer安装第三方依赖包

Laravel5

现支持 PHP5.6、PHP7.0,部分依赖有改造,如需手动安装 Composer 第三方包,需要将 ModStart 私有源加入到 composer.json 中,避免 ModStart 更新时的私有包获取失败。

{
    // ...
    "repositories": [
        {
            "type": "composer",
            "url": "https://modstart.com/composer"
        }
    ]
    // ...
}
1
2
3
4
5
6
7
8
9
10

Laravel9

{
    // ...
    "repositories": [
        {
            "type": "composer",
            "url": "https://modstart.com/composer_9"
        }
    ]
    // ...
}
1
2
3
4
5
6
7
8
9
10

ModStartCMS 默认已添加该私有源

重要提示:通过 composer 引入第三方依赖包表示锁定版本后期不跟随 ModStart 官方进行升级系统,如需要后期跟随官方升级请参照 模块开发 → 模块引入第三方依赖包 进行手动引入。

# 请求和响应

默认情况下,所有接口交互都采用 POST 的请求方式,页面展示采用 GET 的请求方式。

# 接口统一响应格式

响应使用统一的JSON返回

{
    // 错误码,0表示业务处理正常,非0表示业务处理异常,可以定义多个状态码
    "code": 0,
    // 提示信息
    "msg": "提示信息",
    // 返回数据,根据实际业务使用定义
    "data": {
        //...
    },
    // 跳转地址
    // [js]xxxx : 表示前端执行JS代码
    // [reload] : 表示页面立即刷新 window.location.reload()
    // 其他值    : 表示跳转到改地址
    "redirect": "重定向方式"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

后端代码可以使用 Response (opens new window) 类统一构造该返回结果

use ModStart\Core\Input\Response;
// 构造完整的返回结果
Response::generate($code, $msg, $data = null, $redirect = null);
// 构造一个成功的结果数据
Response::generateSuccessData([ 'foo'=>'bar' ]);
// 构造一个错误提示
Response::generateError('错误提示');
// 构造一个正确提示
Response::generateSuccess('正确提示');
1
2
3
4
5
6
7
8
9

更多使用方式请参考 Response (opens new window)

# 默认响应错误码

在基础包 ResponseCodes (opens new window) 中,定义了常用的响应code

// api-token 为空
const API_TOKEN_EMPTY = 1000;
// 需要登录
const LOGIN_REQUIRED = 1001;
// 验证码错误
const CAPTCHA_ERROR = 1002;
// 无权限
const PERMIT_DENIED = 1003;
// 默认错误
const DEFAULT_ERROR = -1;
1
2
3
4
5
6
7
8
9
10

# 业务异常处理

业务异常处理使用统一的 BizException (opens new window) 处理。

use ModStart\Core\Exception\BizException;
// 抛出一个异常
BizException::throws('错误信息');
// 内容为空时并抛出异常
BizException::throwsIfEmpty('用户不存在', $user);
// 内容不为空时并抛出异常
BizException::throwsIfNotEmpty('用户不存在', $user);
// 条件判断并抛出异常
BizException::throwsIf('记录不存在', empty($record));
// 自定义错误页面
BizException::throws('没有权限,请升级', [
    'view' => 'theme.default.pc.upgradeMember',
    'viewData' => [
        'username' => '张三'
    ]
]);
// 自定义状态页面,Web请求时会自动转换为标准错误页面,Ajax请求时会自动转换为标准返回
BizException::throws('资源不存在', [
    'statusCode' => 404,
]);
BizException::throws('没有权限', [
    'statusCode' => 404,
]);
BizException::throws('资源处理出错', [
    'statusCode' => 500,
]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

使用 BizException (opens new window) 抛出的异常,异常处理模块会自动对异常进行转换。

如果请求是 Ajax ,结果会自动转换为标准返回,如图:

{
  "code":-1,
  "msg":"错误信息"
}
1
2
3
4

如果请求是普通页面,会转换为标准错误页面,如图:

# 数据库使用规范

目前使用 MySQL 作为默认数据库,创建数据库表时,请始终保持至少三个字段(主键、创建时间、更新时间)。

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateXxx extends Migration
{
    public function up()
    {
        Schema::create('resume', function (Blueprint $table) {
            // 定义数据表主键ID
            $table->increments('id');
            // 定义数据表创建时间和更新时间 created_at 和 updated_at
            $table->timestamps();
            // 其他字段
        });
    }
    // ...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • 表名:的使用 模块名_表名,格式为小写+下划线。

# 请求会话保持机制

在Web应用程序中,我们经常要跟踪用户身份。当一个用户登录成功后,如果他继续访问其他页面,程序需要继续记录他的身份。

HTTP协议是一个无状态协议,即Web应用程序无法区分收到的两个HTTP请求是否是同一个浏览器发出的。为了跟踪用户状态,服务器可以向浏览器分配一个唯一ID,并以Cookie的形式发送到浏览器,浏览器在后续访问时总是附带此Cookie,这样,服务器就可以识别用户身份。

# Web 功能组

Web 目录中的请求,通过使用 Laravel 自带的 Session 机制,可以很方便的管理会话。后台只需要通过如下方法获取:

  • Session::get 获取会话变量
  • Session::put 设置会话变量
  • Session::forget 删除会话变量

具体可参考 Laravel Session

# Api 功能组

Api目录中的请求,需要携带 api-token 请求头。

  • 第一次发起请求该值留空即可,返回的响应头中会在服务端生成 api-token
  • 在所有接口交互过程中,当响应头中存在 api-token 时,需要覆盖客户端的 api-token 值。
  • 通常第一个请求接口无需携带 api-token 信息,如配置接口 /api/config 、登录接口 /api/login

具体逻辑可参考 SessionMiddleware.php (opens new window)

Laravel 的 Cookie 配置信息配置文件位于 config/session.php,具体可参考以下几个配置

  • lifetime:会话有效期,直接控制 Cookie 的有效期,单位分钟,默认为 120 表示 2 小时
  • expire_on_close:关闭浏览器是否立即过期
  • path:Cookie 的 Path
  • domain:Cookie 的 域名

系统默认的Cookie是加密的,如果不需要加密,可以禁用 Cookie 的加密中间件。

文件位于:app/Http/Kernel.php

注释掉Cookie加密中间件 \Illuminate\Cookie\Middleware\EncryptCookies::class

# 接口对接与联调

# Api接口对接开发

Api目录中的请求,需要携带 api-token 请求头。

  • 第一次发起请求该值留空即可,返回的响应头中会在服务端生成 api-token
  • 在所有接口交互过程中,当响应头中存在 api-token 时,需要覆盖客户端的 api-token 值。
  • 通常第一个请求接口无需携带 api-token 信息,如配置接口 /api/config 、登录接口 /api/login

具体逻辑可参考 SessionMiddleware.php (opens new window)

# 文件上传与静态资源

# 文件本地存储

系统使用了统一的文件上传+存储方案,文件上传默认存储在 /public/data/ 目录中,默认类型+日期进行组织,类型包括 图片(image)、视频(video)、音频(audio)、文件(file)等,具体可在 vendor/modstart/modstart/config/data.php 设置。

# 云存储支持

系统支持市面上主流云存储,如阿里云OSS、腾讯云COS等(查看模块市场云存储支持)。

通过安装云存储模块+配置即可完成文件上云,安装云存储已上传的文件不受影响。

# 静态文件路径迁移

安装完成云存储后,可以手动迁移已上传的历史文件,通过 文件路径迁移助手 (opens new window) 完成数据库字段静态文件路径的迁移。

# 文件路径修正

使用默认的本地存储,文件存储路径格式为 /data/xxx/xxx/xxx.xx ,对于需要返回给接口需要补全为全路径,可通过以下方法完成。

// 将文件路径修正为带域名的全路径,如果本身是全路径原样反馈
// 如 https://www.example.com/data/xxx/xxx/xxx.xx
\ModStart\Core\Assets\AssetsUtil::fixFull('/data/xxx/xxx/xxx.xx');
1
2
3

# 文件上传方法

文件上传相关的方法都在类 \ModStart\Data\DataManager 中,具体使用可参考文档

// 上传文件
// $category 类别,如 image, file 等
// $filename 文件名
// $content 文件二进制内容
\ModStart\Data\DataManager::upload($category, $filename, $content);

// 根据文件路径删除文件上传记录
// $path 文件路径
\ModStart\Data\DataManager::deleteByPath($path);
1
2
3
4
5
6
7
8
9

# 后台管理

# 后台管理员相关操作

// 使用的 Admin 类完整路径为
use ModStart\Admin\Auth\Admin;
// 判断当前管理员是否已登录
Admin::isLogin();
// 当前已登录管理员的ID
$adminUserId = Admin::id();
// 根据管理员ID获取管理员信息
Admin::get( $adminUserId );
// 增加管理员信息日志
Admin::addInfoLog( $adminUserId, '日志摘要', ['数据'=>'数据值'] );
// 增加管理员错误日志
Admin::addErrorLog( $adminUserId, '错误摘要', ['数据键'=>'数据值'] );
// 如果两个数组数据不相同记录日志
Admin::addInfoLogIfChanged( $adminUserId, '数据改变了', ['数据'=>'数据值旧'], ['数据'=>'数据值新'] );
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 后台免登陆接口请求

  • 要求:(MSCore >= 3.6.0)
  • 后台接口指 module/Xxx/Admin 中的接口

# 免登陆接口使用说明

系统提供了后台接口请求免登陆的功能,请求时后台接口时在http请求头中携带以下参数

Header名称 Header值 示例值
auth-admin-user-id 后台管理员ID 1
auth-admin-timestamp 当前时间戳 单位为秒
auth-admin-request-id 请求ID 随机字符串,至少为10位,每次请求不同
auth-admin-sign 签名 为32位ID值,签名计算方法如下
// 管理员ID
$adminUserId = 1;
// 管理员用户名
$adminUserName = 'admin';
// 管理员密码MD5值(参考 admin_user 中的 password 字段 和 passwordSalt 字段)
$adminPassword = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$adminPasswordSalt = 'xxxxxxxxxxx';
// 当前时间戳
$timestamp = time();
// 随机字符串,保证每次请求随机字符串不同
$requestId = uniqid();
// 拼接字符串
$md5String = "$timestamp:$requestId:$adminUserId:$adminUserName:$adminPassword:$adminPasswordSalt";
// 计算签名
$sign = md5($md5String);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 免登陆请求示例代码

$adminUserId = 1;
$adminUserName = 'cms';
$adminPassword = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$adminPasswordSalt = 'xxxxxxxxxx';
$timestamp = time();
$requestId = uniqid();
$md5String = "$timestamp:$requestId:$adminUserId:$adminUserName:$adminPassword:$adminPasswordSalt";
$sign = md5($md5String);
$ret = CurlUtil::post('http://example.com/admin/site/config/setting', [
    'siteName'=>'网站名称'
], [
    'header' => [
        'auth-admin-user-id' => $adminUserId,
        'auth-admin-timestamp' => $timestamp,
        'auth-admin-request-id' => $requestId,
        'auth-admin-sign' => $sign,
    ]
]);
print_r($ret);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 模块开发兼容性问题

为了同时兼容 Laravel 5.1 和 Laravel 9.0,PHP 写法需要同时兼容 PHP 5.x 和 PHP 8.x 的语法。除此之外,一直的框架兼容性问题如下。

# Blade 输出变量

✅ 输出变量或默认值需要
{{ empty($param) ? '默认值' : $param }}

❌ 以下写法不兼容
{{ $param or '默认值' }} → 只兼容 Laravel 5.1
1
2
3
4
5

# Event 事件触发

✅ 封装的兼容性事件触发
\ModStart\Core\Util\EventUtil::fire( $event )

❌ 以下写法不兼容
Event::fire( $event )
Event::dispatch( event )
1
2
3
4
5
6

# Hook

Hook是用于在指定位置调用代码,可以用来代码插件式的输出,方便开发更多的模块。

# 使用方式

比如在页面的尾部输出一行代码,可以在 ModuleServiceProvider 中这样实现:

\ModStart\Core\Hook\ModStartHook::subscribe('PageBodyAppend', function () {
    return '在Body尾部输出一行代码';
});
1
2
3

# 目前已支持的Hook

名称 说明
PageHeadAppend 自适应页面 <head> 标签尾部(包括弹窗)
PageBodyAppend 自适应页面 <body> 标签尾部(包括弹窗)
DialogPageHeadAppend 自适应弹窗页面 <head> 标签尾部(包括弹窗)
DialogPageBodyAppend 自适应弹窗页面 <body> 标签尾部(包括弹窗)
MobilePageHeadAppend 手机页面 <head> 标签尾部
MobilePageBodyAppend 手机页面 <body> 标签尾部
AdminPageHeadAppend 后台管理页面 <head> 标签尾部(已登录,包括弹窗)
AdminPageBodyAppend 后台管理页面 <body> 标签尾部(已登录,包括弹窗)
AdminLoginHeadAppend 管理员登录页面 <head> 标签尾部
AdminLoginBodyAppend 管理员登录页面 <body> 标签尾部

如果你是模块开发者:模块中的Hook应该在模块的说明

# 多语言

# 系统多语言支持

# 翻译文件位置

ModStart从底层架构支持多语言。多语言翻译文件位于以下路径:

  • resources/lang/zh/xxx.php
  • resources/lang/en/xxx.php

# 翻译文件格式

return [
    'Message' => '消息',
    'Error Msg Is %s' => '错误为 %s',
    // ...
];
1
2
3
4
5

# 系统如何确定多语言

系统按照以下顺序来确定当前语言:

  • routeLocale:路由中的语言参数,比如 http://example.com/zh/xxx 中的 zh,需要指定路由参数为 locale
  • sessionLocale:当前会话使用的语言,由 Session 中的 _locale 值决定;
  • i18nLocale:模块 I18n 模块设定的默认语言,如果没安装 I18n 模块,则忽略。
  • locale:系统设定的默认语言,为 config('app.locale') 的值;
  • fallbackLocale:系统设定的回退语言,为 config('app.fallback_locale') 的值。

# 代码调用多语言

// 没有参数
L('xxx.Message')
// 带有参数
L('xxx.Error Msg Is %s', '错误信息')
1
2
3
4

# 模块多语言支持

# 翻译文件位置

模块多语言翻译文件位于模块的路径:

  • module/Xxx/Lang/zh.php
  • module/Xxx/Lang/en.php
  • ...

# 翻译文件格式

return [
    'Message' => '消息',
    'Error Msg Is' => '错误为 %s',
    // ...
];
1
2
3
4
5

# 代码调用多语言

// 没有参数,Xxx 表示模块名
LM('Xxx', 'Message')
// 带有参数,Xxx 表示模块名
LM('Xxx', 'Error Msg Is', '错误信息')
1
2
3
4

# 系统如何切换多语言

可以通过程序切换 Session 中的变量 _locale 来实现。

如:

// 切换到中文
Session::put('_locale', 'zh');
// 切换到英文
Session::put('_locale', 'en');
1
2
3
4

# 系统多语言示例

resources/lang/zh/xxx.phpresources/lang/en/xxx.php 中,定义多语言:

// 语言包文件 resources/lang/zh/xxx.php
return [
    'Message' => '消息',
    'Error Msg Is %s' => '错误为 %s',
];
// 语言包文件 resources/lang/en/xxx.php
return [
    'Message' => 'Message',
    'Error Msg Is %s' => 'Error is %s',
];
1
2
3
4
5
6
7
8
9
10

xxx.blade.php 视图文件中,输出多语言:

<div>
    不带参数语言:{{ L('xxx.Message') }}
</div>
<div>
    带参数语言:{{ L('xxx.Error Msg Is %s', '错误信息') }}
</div>
1
2
3
4
5
6

可以在 Controller 中切换语言:

class XxxController
{
    public function index() {
        // 切换到中文
        Session::put('_locale', 'zh');
        // 切换到英文
        Session::put('_locale', 'en');
    }
}
1
2
3
4
5
6
7
8
9

# 任务调度

使用 Laravel 的任务调度,可以实现系统计划执行任务。

# 在模块中注册任务调度

实现一个任务调度Provider

<?php
namespace Module\Xxx\Provider;

use Module\Vendor\Provider\Schedule\AbstractScheduleBiz;

class ModuleXxxScheduleBiz extends AbstractScheduleBiz
{
    public function cron()
    {
        // 每分钟调度
        return $this->cronEveryMinute();
    }

    public function title()
    {
        return '测试任务调度';
    }

    public function run()
    {
        Log::info('任务已经执行');
    }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

注册任务调度

ScheduleBiz::register(ModuleXxxScheduleBiz::class);
1

# 开启调度器

Cron 是 UNIX、SOLARIS、LINUX 下的一个十分有用的工具,通过 Cron 脚本能使计划任务定期地在系统后台自动运行。这种计划任务在 UNIX、SOLARIS、LINUX下术语为 Cron Jobs。

下面是你唯一需要添加到服务器的 Cron 条目:

* * * * * www /xx/bin/php /www/example.com/artisan schedule:run >> /dev/null 2>&1
1
  • * * * * * 每分钟调度一次
  • /xxx/bin/php 替换成 PHP 的运行路径,通常为 /usr/bin/php
  • www PHP 执行用户

该 Cron 将会每分钟调用命令调度器,用于调度模块中定义的相关任务。

# 内置的调度任务

名称 说明
DataTempCleanScheduleBiz 上传的临时文件清理(删除超过1天未使用的上传临时文件)
TempFileCleanScheduleBiz 系统临时本地文件清理(删除超过7天未使用的文件)

# 队列调度

队列的目的是将耗时的任务延时处理,比如发送邮件、文档转换处理等,从而大幅度缩短 Web 请求和响应的时间。

队列配置文件存放在 config/queue.php。每一种队列驱动的配置都可以在该文件中找到,包括数据库、Beanstalkd、Amazon SQS、Redis以及同步(本地使用)驱动。

# 如何使用 MySQL 作为队列驱动

① 生成数据库队列表迁移文件

在执行该步骤前,请先检查迁移文件 database/migrations/xxxx_xx_xx_xxxxxx_create_jobs_table.php 是否存在,如果已存在直接跳过第①步

# 运行该命令之前请检查是否存在迁移文件 database/migrations/xxxx_xx_xx_xxxxxx_create_jobs_table.php
# 如果存在直接跳过该步骤
php artisan queue:table
# 运行该命令之前请检查是否存在迁移文件 database/migrations/xxxx_xx_xx_xxxxxx_create_failed_jobs_table.php
# 如果存在直接跳过该步骤
php artisan queue:failed-table
1
2
3
4
5
6

这一步会生成数据库迁移文件 database/migrations/xxxx_xx_xx_xxxxxx_create_jobs_table.phpdatabase/migrations/xxxx_xx_xx_xxxxxx_create_failed_jobs_table.php

② 执行数据库迁移文件

php artisan migrate
1

③ 在 .env 文件配置队列驱动为数据库

QUEUE_DRIVER=database
QUEUE_CONNECTION=database
1
2

④ 运行队列进程测试运行

如果队列中有任务,以下命令会自动执行一个任务,查看是否报错,无报错表示配置成功

Laravel5

/xxx/bin/php /www/example.com/artisan queue:work database --queue=default --sleep=3 --tries=1 --timeout=86400
1
  • /xxx/bin/php 替换成 PHP 的运行路径,通常为 /usr/bin/php
  • default 为队列名称,默认为 default,还有其他队列如文档转换 FileConvert

Laravel9

/xxx/bin/php /www/example.com/artisan --queue=default queue:work database --once --sleep=3 --tries=1 --timeout=86400
1
  • /xxx/bin/php 替换成 PHP 的运行路径,通常为 /usr/bin/php
  • default 为队列名称,默认为 default,还有其他队列如文档转换 FileConvert

# 如何使用 Redis 作为队列驱动

① 修改 .env 文件,配置 Redis 连接信息

REDIS_HOST=x.x.x.x
REDIS_PASSWORD=yourpassword
REDIS_PORT=6379
1
2
3

② 在 .env 文件配置队列驱动为 Redis

QUEUE_DRIVER=redis
QUEUE_CONNECTION=redis
1
2

③ 运行队列进程测试运行

如果队列中有任务,以下命令会自动执行一个任务,查看是否报错,无报错表示配置成功

Laravel5

/xxx/bin/php /www/example.com/artisan queue:work redis --queue=default --sleep=3 --tries=1 --timeout=86400
1
  • /xxx/bin/php 替换成 PHP 的运行路径,通常为 /usr/bin/php
  • default 为队列名称,默认为 default,还有其他队列如文档转换 FileConvert

Laravel9

/xxx/bin/php /www/example.com/artisan --queue=default queue:work redis --once --sleep=3 --tries=1 --timeout=86400
1
  • /xxx/bin/php 替换成 PHP 的运行路径,通常为 /usr/bin/php
  • default 为队列名称,默认为 default,还有其他队列如文档转换 FileConvert

# 使用 Supervisor 管理队列进程

如果你使用的是 ssh 运行的队列进程,当 ssh 连接断开时,该进程会自动停止。

Supervisor 是 Linux 系统中常用的进程守护程序,如果队列进程 queue:work 意外关闭,它会自动重启启动队列进程。

Supervisor 参考配置

Laravel5

[program:queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=/xxx/bin/php /www/example.com/artisan queue:listen database --sleep=5 --memory=4096 --tries=1 --timeout=86400
autostart=true
autorestart=true
user=www
numprocs=1
redirect_stderr=true
stdout_logfile=/tmp/worker.log
1
2
3
4
5
6
7
8
9
  • /xxx/bin/php 替换成 PHP 的运行路径,通常为 /usr/bin/php
  • default 为队列名称,默认为 default,还有其他队列如文档转换 FileConvert
  • command 表示执行的命令
  • user 表示启动进程的用户
  • numprocs 可以控制队列进程的数量,即同时执行的任务数

Laravel9

[program:queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=/xxx/bin/php /www/example.com/artisan queue:work database --queue=default --sleep=3 --tries=1 --timeout=86400
autostart=true
autorestart=true
user=www
numprocs=1
redirect_stderr=true
stdout_logfile=/tmp/worker.log
1
2
3
4
5
6
7
8
9
  • /xxx/bin/php 替换成 PHP 的运行路径,通常为 /usr/bin/php
  • default 为队列名称,默认为 default,还有其他队列如文档转换 FileConvert
  • command 表示执行的命令
  • user 表示启动进程的用户
  • numprocs 可以控制队列进程的数量,即同时执行的任务数

# 性能追踪与优化

系统支持记录 LONG_REQUEST、LONG_SQL、MASS_REQUEST_SQL 多种指标,用于性能优化分析。 通过在配置文件 .env 增加 TRACK_PERFORMANCE=true 开启新能追踪。

开启后,如果未生效可清除下缓存(删除 bootstrap/cache/ 目录下的所有文件),日志中可能会出现性能信息。

# LONG_REQUEST 慢请求

开启性能追踪配置后,请求过程中响应超过 1000ms 的请求会被记录到日志中。

LONG_REQUEST GET [/xxx/xxx] 1500ms {"foo":"bar"}
1

# LONG_SQL 慢SQL

开启性能追踪配置后,请求过程中执行时间超过 500ms 的 SQL 会被记录到日志中。

LONG_SQL 600ms SELECT * FROM `users` WHERE `id` = ?, [5]
1

# MASS_REQUEST_SQL

开启性能追踪配置后,请求过程如果SQL查询超过 10 次,该请求信息会被记录到日志中。

MASS_REQUEST_SQL GET [/xxx/xxx] 15 {"foo":"bar"} -> ["SELECT * FROM xxx WHERE id =?, [1]",...]
1

# 名词解释

名词 说明
应用 和业务相关的代码不能独立成为模块复用,代码在 app/ 目录,用于系统个性化的需求开发。
模块 每个模块有比较独立的功能,代码在 module/ 目录,每个模块一个目录,模块市场安装的模块也在该目录中。
功能组 位于模块目录中,常见的功能组有 WebApiAdminOpenApi ,分别提供不同的分组功能
Web 功能组-前台管理,处理用户前台相关功能
Admin 功能组-后台管理,处理后台管理相关功能
Api 功能组-Api接口,处理用户端前台界面、手机端、小程序等请求
OpenApi 功能组-OpenApi开放接口,处理系统对外提供的标准接口,通常同时AppId和AppSecret授权调用
Last Updated: 5 months ago