很多人搞开发的程序员都有着一颗创业心,但手里只有锤子和钉子(技术),对于做什么都没有什么想法(产品),个人觉得主要是因为程序员技术至上的思维,沉迷钻研技术,忽略了工作生活中的需求。正所谓需求来源于生活,so,如何通过技术实现需求,是每个程序员都需要思考的问题。作为一名程序员,你是否有过这样的感觉你觉得自己技术很牛,但你不知道该如何应用到实际工作中,你觉得自己技术不过关,但你又不知道如何突破瓶颈。今天分享一个我日常工作中提效的一个方法,并将整个版本的迭代过程分享给大家,希望能给你一些启发。 项目源码:github.com/Benny66/dev...
背景
我接手了一个项目,这个项目被拆分成多个不同的微服务,也有着不同的客户端(PC端、移动端),每一个服务都是一个独立的项目仓库,以下是该项目微服务架构缩略图:
在日常的开发过程中,经常需要启动、切换多个不同的服务来进行本地调试,比如启动一个后端服务,启动一个前端服务,启动一个数据计算服务等等。每次启动服务都需要打开一个新的命令行窗口,输入命令,等待服务启动完成,然后才能进行下一步操作。这样的工作效率非常低下,特别是当你需要启动的服务很多的时候,效率就更低了。
为了提高效率,我们可以把多个服务启动命令整合到一起,然后通过一个脚本来启动所有服务。这样只需要打开一个命令行窗口,输入脚本命令,就可以启动所有服务,而且可以同时启动多个服务,大大提高了工作效率。
技术选型
因为本地使用mac环境开发,所以选用shell脚本来实现。
第一版本
分析了平时工作中启动服务的流程,发现每次启动服务都需要打开一个新的命令行窗口,输入命令(yarn dev 或者 php bin/swoft http:start),等待服务启动完成,然后打开另一个服务,重复上面的操作。 所以,我们可以把启动命令整合到一起,然后通过一个脚本来启动所有服务。
这个版本包括了启动脚本和关闭脚本,启动脚本会启动所有服务,关闭脚本会杀死所有服务的进程。
- 启动脚本原理就是遍历所有服务的绝对目录,然后启动服务的命令,并将输出写入日志文件。
- 启动命令:./start.sh
- 关闭脚本通过pgrep遍历进程列表,然后kill掉所有进程。
- 关闭命令:./kill.sh
启动脚本
bash
#!/bin/bash
# 执行本脚本需添加脚本权限
# chmod +x start.sh
# 定义日志文件路径
LOG_DIR=/Users/shahao/Project/tencent/script
# 定义函数,启动指定目录下的命令,并将输出写入日志文件
function start_command {
local dir=$1
local command=$2
local log_file=$3
echo "Starting $command in $dir ..."
cd "$dir" || { echo "Failed to change directory to $dir."; exit 1; }
# 本地还有其他前端项目,这个项目需要切换node版本为16
if [ "$command" == "yarn dev" ]; then
source ~/.nvm/nvm.sh
nvm use 16
fi
nohup $command 2>&1 | tee "$log_file" &
echo "Started $command."
}
# 启动 tpp_flow_srv,自行替换路径、脚本启动目录、日志存储名称
# start_command "/absolute_path" "your_cmd" "$LOG_DIR/your_log_filename.txt"
start_command "/Users/shahao/Project/tencent/elf" "air" "$LOG_DIR/tpp_flow_srv_log.txt"
# 启动 tpp_flow_web
start_command "/Users/shahao/Project/tencent/tpp_flow_web" "pnpm dev" "$LOG_DIR/tpp_flow_web_log.txt"
# 启动 dev_frame_service
start_command "/Users/shahao/Project/tencent/dev_frame_service" "php bin/swoft http:start" "$LOG_DIR/dev_frame_service_log.txt"
# 启动 dev_platform_web
start_command "/Users/shahao/Project/tencent/dev_platform_web" "yarn dev" "$LOG_DIR/dev_platform_web_log.txt"
关闭脚本
bash
#!/bin/bash
# 定义需要杀死的进程列表
processes=(
"php bin/swoft http:start"
"air"
"node /Users/shahao/.yarn/bin/yarn.js dev"
"node /usr/local/bin/pnpm dev"
)
# 定义函数,杀死指定进程名的进程
function kill_process {
local process_name=$1
local pid=$(pgrep -f "$process_name")
if [[ -n $pid ]]; then
kill $pid
echo "已杀死进程 $process_name $pid"
else
echo "未找到进程 $process_name"
fi
}
# 遍历进程列表,执行杀死进程的操作
for process in "${processes[@]}"; do
kill_process "$process"
done
第二版本
第一个版本将启动的命令写死在脚本中,这样每次启动都需要修改脚本,不利于后期维护。
第二个版本迭代
1、支持参数化启动,通过参数指定要启动的服务,这样可以灵活地启动不同的服务。
2、修复一下关闭脚本的bug。通过pid关闭进程但实际上会服务端口一直在占用,所以kill掉进程失败后,通过端口查询进程是否存在,如果存在,则kill掉进程。
3、新增查看权限项目服务状态参数,可以查看各个服务的运行状态。
4、shell脚本优化,使用函数封装逻辑,提高可读性。
-
定义参数base为基础服务底座,user为用户端服务,rights为业务端服务,admin为超管端服务。
-
启动脚本:./start.sh -r rights
bash
# 初始化数组
params=() # 使用数组来存储权限值
# 检查参数数量
if [[ $# -eq 0 ]]; then
echo "错误:没有提供参数。"
exit 1
fi
# 遍历所有传入的参数
while [[ $# -gt 0 ]]; do
case "$1" in
-r | run | -k | kill | status)
if [[ -n "$2" ]]; then
process_option "$1" "$2" params
# 根据选项设置 action 变量
case "$1" in
-r) action='run' ;;
-k) action='kill' ;;
status) action='status' ;;
esac
shift 2 # 移过选项和它的参数
else
echo "错误:$1 选项需要一个参数。"
exit 1
fi
;;
-h | --help)
help_info
exit 0
;;
*)
echo "未知的选项 $1"
exit 1
;;
esac
done
# .. 省略其他代码
# 启动命令
function run {
isRunBaseProject=false
# 遍历数组
for param in "${params[@]}"; do
echo "StartProcessing: $param"
if [[ "$param" == "rights" ]]; then
if [[ "$isRunBaseProject" == false ]]; then
start_command "$BASE_PROJECT_DIR/dev_frame_service" "php bin/swoft http:start" "$LOG_DIR/dev_frame_service_log.log"
start_command "$BASE_PROJECT_DIR/dev_platform_web" "yarn dev" "$LOG_DIR/dev_platform_web_log.log"
isRunBaseProject=true
fi
# 当 right 为 rights 时,执行 start_command
start_command "$RIGHTS_PROJECT_DIR/rights_web" "yarn dev" "$LOG_DIR/right_rights_web_log.log"
start_command "$RIGHTS_PROJECT_DIR/rights_service" "./shell/watch.sh" "$LOG_DIR/right_rights_service_log.log"
fi
# ...可添加其他的服务启动逻辑
done
}
help_info() {
echo "错误:没有提供参数。"
echo "-r 选项:启动权限项目服务,参数为权限值,如 -r base,user,rights,admin 启动全部权限项目服务。"
echo "如:./rights.sh -r base,user,rights,admin"
echo "-k 选项:杀死权限项目服务,参数为权限值,如 -k base,user,rights,admin 杀死全部权限项目服务。"
echo "如:./rights.sh -k base,user,rights,admin"
echo "status 选项:查看权限项目服务状态。"
echo "如:./rights.sh status"
echo "-h 选项:显示帮助信息。"
}
第三版本
第二个版本在启动服务虽然可以灵活地启动不同的服务,但还是存在一些问题:项目的目录,启动命令都写死在脚本中,新增服务需要修改脚本,不利于后期维护。
第三个版本迭代
1、支持配置文件启动,通过配置文件指定要启动的服务,这样可以灵活地配置启动参数。
2、支持自定义启动服务参数,通过参数指定要启动的服务,这样可以灵活地启动不同的服务。
3、优化脚本参数,使用函数封装逻辑,提高可读性。
.env 文件位于脚本同一目录下,它包含了运行脚本所需的配置信息。以下是 .env 文件的配置项示例:
ini
# .env 文件
# .env 文件
LOG_DIR="/Users/shahao/Project/tencent/script" # 日志文件存放目录
PROJECT_NAMES="BASE,RIGHTS"
BASE_PROJECT_DIR="/Users/shahao/Project/tencent" # 基础项目目录
BASE_PROJECT_NAMES="TPP" # 项目为TPP
BASE_TPP_FRONTEND_PROJECT_NAME="dev_platform_web" # TPP项目的前端服务
BASE_TPP_FRONTEND_RUN_CMD="yarn dev" # TPP项目的前端服务启动命令
BASE_TPP_BACKEND_PROJECT_NAME="dev_frame_service" # TPP项目的后端服务
BASE_TPP_BACKEND_RUN_CMD="./shell/watch.sh" # TPP项目的后端服务启动命令
#...其他忽略的配置项
请确保在运行脚本前,您的 .env 文件已经正确配置了上述路径。
示例
- 启动所有权限项目服务:
bash
./rights.sh -r rights user
- 杀死所有权限项目服务:
bash
./rights.sh -k base tpp
- 查看服务状态:
bash
./rights.sh status rights user
自定义启动服务
自定义启动服务,需要在启动命令后面加上-c选项,如:
bash
# 自定义项目配置
CUSTOM_PROJECT="BASE,RIGHTS" # 自定义项目名称
CUSTOM_BASE_SERVER="TPP" # 自定义项目的服务名称
CUSTOM_RIGHTS_SERVER="USER,RIGHTS" # 自定义项目的服务名称
# 启动服务
./rights.sh -c
总结
通过脚本来启动服务,可以大大提高工作效率,提高工作质量。通过配置文件来配置启动参数,可以灵活地启动不同的服务,提高工作效率。通过自定义启动服务参数,可以灵活地启动不同的服务,提高工作效率。 希望通过这篇文章,能给你一些启发,提高工作效率,提高工作质量。如果有什么建议,欢迎留言。