如何在go中实现程序的优雅退出,go-kratos源码解析
使用kratos这个框架有近一年了,最近了解了一下kratos关于程序优雅退出的具体实现。
这部分逻辑在app.go文件中,在main中,找到app.Run方法,点进入就可以了
它包含以下几个部分:
-
App结构体:包含应用程序的配置选项和运行时状态。
-
New函数:创建一个App实例。
-
Run方法:启动应用程序。主要步骤包括:
- 构建ServiceInstance注册实例
- 启动Server
- 注册实例到服务发现
- 监听停止信号
-
Stop方法:优雅停止应用程序。主要步骤包括:
- 从服务发现中注销实例
- 取消应用程序上下文
- 停止Server
-
buildInstance方法:构建用于服务发现注册的实例。
-
NewContext和FromContext函数:给Context添加AppInfo,便于后续从Context获取。
核心的逻辑流程是:
- 创建App实例
- 在App.Run()里面启动Server,注册实例,监听信号
- 接收到停止信号后会调用App.Stop()停止应用
我们先对Run方法进行一个源码进行查看
// Run executes all OnStart hooks registered with the application's Lifecycle.
func (a *App) Run() error {// 构建服务发现注册实例instance, err := a.buildInstance() if err != nil {return err}// 保存实例 a.mu.Lock()a.instance = instancea.mu.Unlock()// 创建错误组eg, ctx := errgroup.WithContext(NewContext(a.ctx, a))// 等待组,用于等待Server启动完成wg := sync.WaitGroup{}// 启动每个Serverfor _, srv := range a.opts.servers {srv := srv eg.Go(func() error {// 等待停止信号<-ctx.Done() // 停止ServerstopCtx, cancel := context.WithTimeout(a.opts.ctx, a.opts.stopTimeout)defer cancel()return srv.Stop(stopCtx)})wg.Add(1)eg.Go(func() error {// Server启动完成wg.Done() // 启动Server return srv.Start(NewContext(a.opts.ctx, a)) })}// 等待所有Server启动完成wg.Wait()// 注册服务实例if a.opts.registrar != nil {rctx, rcancel := context.WithTimeout(ctx, a.opts.registrarTimeout)defer rcancel()if err := a.opts.registrar.Register(rctx, instance); err != nil {return err}}// 监听停止信号c := make(chan os.Signal, 1)signal.Notify(c, a.opts.sigs...)eg.Go(func() error {select {case <-ctx.Done():return nilcase <-c:// 收到停止信号,停止应用------------- ⬅️注意此时return a.Stop() }})// 等待错误组执行完成if err := eg.Wait(); err != nil && !errors.Is(err, context.Canceled) {return err}return nil
}
核心逻辑就是这里⬇️,使用signal.Notify去监听操作系统给出的停止信号。
// 监听停止信号c := make(chan os.Signal, 1)signal.Notify(c, a.opts.sigs...)eg.Go(func() error {select {case <-ctx.Done():return nilcase <-c:// 收到停止信号,停止应用return a.Stop() }})
然后调用了Stop方法,我们再看下Stop的源码
// Stop gracefully stops the application.
func (a *App) Stop() error {// 获取服务实例 a.mu.Lock()instance := a.instancea.mu.Unlock()// 从服务发现注销实例if a.opts.registrar != nil && instance != nil {ctx, cancel := context.WithTimeout(NewContext(a.ctx, a), a.opts.registrarTimeout)defer cancel()if err := a.opts.registrar.Deregister(ctx, instance); err != nil {return err}}// 取消应用上下文if a.cancel != nil {a.cancel() }return nil
}
主要步骤是:
1. 获取已经保存的服务实例
2. 如果配置了服务发现,则从服务发现中注销该实例
3. 取消应用上下文来通知应用停止在Run方法中,我们通过context.WithCancel创建的可取消的上下文Context,在这里通过调用cancel函数来取消该上下文,以通知应用停止。取消上下文会导致在Run方法中启动的协程全部退出,从而优雅停止应用。所以Stop方法比较简单,关键是利用了Context来控制应用生命周期。
我们可以注意到,在Run方法中,我们使用到了一个signal包下的Notify方法来对操作系统的关闭事件进行监听,这个是我们动作的核心,我把这部分单独整理在了另一篇文章中。
通过对操作系统事件的监听,我们就可以对一些必须完成的任务进行优雅地停止,如果有一些任务必须完成,我们可以在任务开始使用 wg := sync.WaitGroup{} 来对任务进行一个Add操作,当所有任务完成,监听到操作系统的关闭动作,我们需要使用wg.wait() 等待任务完成再进行退出。以实现一个优雅地启停。
相关文章:
如何在go中实现程序的优雅退出,go-kratos源码解析
使用kratos这个框架有近一年了,最近了解了一下kratos关于程序优雅退出的具体实现。 这部分逻辑在app.go文件中,在main中,找到app.Run方法,点进入就可以了 它包含以下几个部分: App结构体:包含应用程序的配置选项和运行时状态。 …...
Appium+python自动化(二十八)- 高级滑动(超详解)
高级溜冰的滑动 滑动操作一般是两点之间的滑动,这种滑动在这里称其为低级的溜冰滑动;就是上一节给小伙伴们分享的。然而实际使用过程中用户可能要进行一些多点连续滑动操作。如九宫格滑动操作,连续拖动图片移动等场景。那么这种高级绚丽的溜…...
github token使用方法
git remote set-url origin https://<githubtoken>github.com/<username>/<repositoryname>.git 在私有仓库的HTTPS的url上加入<githubtoken>即为token url,可以免ssh key登录...
Spring属性注解对配置项名称的自动转换
一、前言 在Spring中,我们经常需要将配置文件中的属性值注入到Java类中。Spring提供了两个主要的注解来实现这一功能:Value 和 ConfigurationProperties。其中 ConfigurationProperties支持将配置项名称与Java类中的属性名进行自动转换,包括…...
Docker 安全 Docker HTTPS请求过程与配置
Docker 容器安全注意点 尽量别做的事 尽量不用 --privileged 运行容器(授权容器root用户拥有宿主机的root权限) 尽量不用 --network host 运行容器(使用 host 网络模式共享宿主机的网络命名空间) 尽量不在容器中运行 ssh 服务 尽…...
DevOps(三)
CD(二) 1. 整体流程2. 环境准备1. jenkins安装2. 编译安装git3. docker安装4. docker-compose安装5. sonarqube安装6. harbor安装7. gitlab私服8. maven安装9. Nexus部署10. K8s部署3. 安装java及编写代码3.1 安装java3.2 安装IntelliJ IDEA3.3 安装tomcat3.4 安装maven3.5 c…...
AOP的妙用
一、改代码 自定义注解用于提示该代码已经在AOP中重构了 public interface ReviseToAop {// 用于记录修改状态String value() default ""; }使用注解(无意义,只是表名被修改) ReviseToAop("修改于:2023/7/30&quo…...
CAN转ETHERCAT网关将CAN 总线和 ETHERCAT 网络连接方法
由于好多现场会出现将CAN总线的设备接到EtherCAT网络中,由于协议的不相同,不能直接进行连接,现需一种能同时兼容CAN 总线和ETHERCAT网络的一种设备,由此捷米JM-ECT-CAN 是自主研发的一款 ETHERCAT 从站功能的通讯网关。该产品主要…...
【大数据趋势】7月30日 汇率,恒指期货的大数据趋势概率分析。
1. 数据源头之一 : 汇率变化 从程序模拟趋势来看,美元在持续弱势状态,周线上正在构建一个新的下跌趋势,而且正在反抽过程中,即将完成,如果没有外部干预,会顺势往下。从月线来看,高点逐步降低&a…...
mac使用mvn下载node-sass 会Binary download failed, trying source
m1 上使用nvm 以下node的版本可以直接下载(Binary download,而不是 trying source)而不用切换mac cpu架构 zhiwenwenzhiwenwendeMBP cockpit % nvm install 14.15.5 Downloading and installing node v14.15.5... Downloading https://node…...
【C++】开源:Muduo网络库配置与使用
😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍Muduo网络库配置与使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下…...
VCS ICO - Intelligent Coverage Optimization
ico是vcs提供的用于优化覆盖率的feature;一般用户通过dist solver bofore等约束了变量的随机概率,而ico会在用户约束的基础上,做一些自动“修正”,以此来优化随机激励,提高随机多样性,加速覆盖率收敛&#…...
【分布式系统】分布式系统的8个谬误
网络可靠 对于分布式系统来说,网络、计算、存储是三大基石,系统之间进行拆分隔离之后,那么必定存在网络通讯,而网络是最不可靠的。 不管是从硬件层面还是软件层面来说,网络是不可靠的。(断电、配置错误、ID…...
tinkerCAD案例:25. 量角器 - 测量角度
tinkerCAD案例:25. 量角器 - 测量角度 原文 Now we’re going to make a protractor! A Protractor is one of the most basic, but essential, tools for making measurements. It is, then, surprising that the modern protractor is barely over 200 years ol…...
Flutter 使用texture_rgba_renderer实现桌面端渲染视频
Flutter视频渲染系列 第一章 Android使用Texture渲染视频 第二章 Windows使用Texture渲染视频 第三章 Linux使用Texture渲染视频 第四章 全平台FFICustomPainter渲染视频 第五章 Windows使用Native窗口渲染视频 第六章 桌面端使用texture_rgba_renderer渲染视频(本…...
linux虚拟机开机后桌面显示CentOS-7.5-x86盘片文件,并且无法远程连接虚拟机?
在虚拟机启动后遇到了显示CentOS-7.5-x86光盘片文件的问题,并且无法远程连接到虚拟机,有几个可能的解决方法: 检查虚拟机设置:确保虚拟机的网络适配器已正确配置,并且虚拟机配置的网络选项是桥接模式或 NAT 模式&#…...
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
AutoConfigurationImportSelector 源码解析 引言主要内容1. ImportSelector 接口2. DeferredImportSelector 接口3. AutoConfigurationImportSelector 功能概述 总结 引言 上篇博文我们了解了 EnableAutoConfiguration 注解,其中真正实现自动配置功能的核心实现者 …...
系统学习Linux-MySQL数据库备份(四)
一、概述 数据库备份是指将数据库中的数据、表格、视图、存储过程、触发器等信息备份到另一个地方,一遍在数据库丢失或损坏时进行恢复,数据库备份是数据库管理中必不可少的一项工作,通过备份可以保护数据库中的数据和业务。 二、数据备份的…...
具身智能controller---RT-1(Robotics Transformer)(中---实验介绍)
6 实验 实验目的是验证以下几个问题: RT-1可以学习大规模指令数据,并且可以在新任务、对象和环境上实现zero-shot的泛化能力?训练好的模型可以进一步混合多种其他数据(比如仿真数据和来自其他机器人的数据)吗?多种方…...
无涯教程-jQuery - load( url, data, callback)方法函数
load(url,data,callback)方法从服务器加载数据,并将返回的HTML放入匹配的元素中。 load( url, [data], [callback] ) - 语法 [selector].load( url, [data], [callback] ) 这是此方法使用的所有参数的描述- url - 包含请求发送到…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
