golang 监听服务的信号,实现平滑启动,linux信号说明详解
作者:胖达喵 发布时间:2024-05-09 10:00:43
标签:golang,监听,信号,平滑
监听服务的信号,实现平滑启动,linux信号说明
package main
import (
"context"
"fmt"
"golang.org/x/sync/errgroup"
"net/http"
"os"
"os/signal"
"syscall"
)
func main() {
g, ctx := errgroup.WithContext(context.Background())
fmt.Println("服务启动start!")
addr := ":9091"
s :=&http.Server{
Addr: addr,
Handler:http.DefaultServeMux,
}
g.Go(func() error {
http.HandleFunc("/test1", func(writer http.ResponseWriter, request *http.Request) {
fmt.Println("tes1")
writer.Write([]byte("tes1"))
})
return s.ListenAndServe()
})
g.Go(func() error {
exit := make(chan os.Signal)
//监听 Ctrl+C 信号
signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM)
select {
case <-exit:
fmt.Println("进程已被取消~")
return s.Shutdown(ctx)
}
})
err := g.Wait()
if err != nil {
fmt.Println(err)
}
fmt.Println("服务启动成功!")
if ctx.Err() !=nil {
fmt.Println(ctx.Err())
fmt.Println("服务关闭成功!")
os.Exit(0)
}
}
补充:golang http服务实现平滑重启
看代码吧~
package main
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"net/http"
"os"
"os/signal"
"time"
)
var logChan = make(chan map[string]interface{})
var requestStatusMap = map[int]bool{}
var done = make(chan bool, 1)
var quit = make(chan os.Signal, 1)
//为什么这样可以平滑重启?
// 正常情况下是server.ListenAndServe() 这个位置hang住整个进程的
// 可以把这个程序看成两部分,1个是web服务的监听部分,一个是处理部分, 如果web服务器不开启了,那么就不能处理新进来的请求了(可以理解为一个带路的)
// 真正让这个请求断掉 是因为主进程(main)被kill
// 所以平滑重启的原理就是,先kill掉web服务器,不让新的请求进来,等现有的全部请求完了,然后结束当前进程
func main() {
server := newServer()
signal.Notify(quit, os.Interrupt)
go monitorKill(server, quit)
server.ListenAndServe()
<-done
}
func newServer() *http.Server {
router := http.NewServeMux()
router.HandleFunc("/hello", sayHello)
return &http.Server{
Addr: ":8262",
Handler: router,
}
}
func monitorKill(server *http.Server, quit <-chan os.Signal) {
<-quit
go shutDown(server)
for {
if len(requestStatusMap) != 0 {
fmt.Println("目前还有进行中的请求,请稍等")
time.Sleep(time.Second * 1)
continue
} else {
close(done)
break
}
}
}
func shutDown(server *http.Server) {
if err := server.Shutdown(context.Background()); err != nil {
fmt.Println(err)
}
}
func sayHello(w http.ResponseWriter, r *http.Request) {
go WriteInfo()//请求写日志
var uniqueId = GenerateRangeNum(1, 1000)
requestStatusMap[uniqueId] = false
url := r.URL.Path
query := r.URL.RawQuery
method := r.Method
a := map[string] interface{}{
"url" : url,
"method" : method,
"query" : query,
"response": "hello world!",
}
logChan<-a
w.Write([]byte("hello world!"))
time.Sleep(time.Second * 10)
delete(requestStatusMap, uniqueId)
}
func WriteInfo() {
info := <-logChan
fileName := "/tmp/weekhomework.log"
_, err := os.Stat(fileName)
if err != nil || os.IsNotExist(err) {
_, _ = os.Create(fileName)
}
f,err := os.OpenFile(fileName, os.O_WRONLY, 0644)
defer f.Close()
if err !=nil {
fmt.Println(err.Error())
} else {
//追加写入 为什么O_APPEND 模式无法写入? todo
n, _ := f.Seek(0, 2)
infostr, _ := json.Marshal(info)
_,err=f.WriteAt([]byte(string(infostr) +"\n"), n)
}
}
func GenerateRangeNum(min int, max int) int {
if min == max {
return min
}
rand.Seed(time.Now().Unix())
randNum := rand.Intn(max-min) + min
return randNum
}
主要思路:
对于每个请求都做记录,处理完成之后做删除。 用一个协程去监控中断信号,有中断信号先把http服务关闭。
如果这个时候还有请求没有处理完,那么就轮训等待,等全部处理完那么就 发出终止信号结束main进程的执行
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。
来源:https://pangda.blog.csdn.net/article/details/116259908
0
投稿
猜你喜欢
- 前言:我目前使用的服务器为centos6.x 系统自带的python的版本为2.6.x,但是目前无论是学习还是使用python,python
- 1.方法详情:parametrize(argnames,argvalues,indirect=False,ids=None,scope=No
- 为了能够使用ERWin能够进行基于MySQL数据库的物理设计,可以采用以下方法步骤(假设你已经有了一个设计好的LOGICAL MODEL):
- 链表由一系列不必在内存中相连的结构构成,这些对象按线性顺序排序。每个结构含有表元素和指向后继元素的指针。最后一个单元的指针指向NULL。为了
- 在日常运维中,如果涉及到用户管理,就一定会用到给用户设置密码的工作,其实吧,平时脑子里觉得设置个密码没什么,但要真让你随手敲一个12位带特殊
- 最近在处理词向量这块,因为平时习惯把处理的词向量保存成文件,但是txt文件读取出来的都是string格式的数字,有必要转成float型上网查
- 钉钉开放平台传送门:https://open.dingtalk.com我司使用钉钉作为内部通讯工具,基本上大家在电脑和手机上都开着,消息可以
- 写在前面好久没更新Blog了,从CRUD Boy转型大数据开发,拉宽了不少的知识面,从今年年初开始筹备、组建、招兵买马,到现在稳定开搞中,期
- 前言压力测试过程中,如果因为资源使用瓶颈等问题引发最直接性能问题是业务交易响应时间偏大,TPS逐渐降低等。而问题定位分析通常情况下,最优先排
- 在向表中插入数据的时候,经常遇到这样的情况:1、首先判断数据是否存在;2、如果不存在,则插入;3、如果存在,则更新。 在 SQL
- 本文实例为大家分享了MySQL安装及配置远程登录教程,供大家参考,具体内容如下一.安装MySQL一.安装MySQL1. sudo apt-g
- 加在< head>中< SCRIPT LANGUAGE="JavaScript">//more
- 概述:前段时间在跟其他公司DBA交流时谈到了mysql跟PG之间在多表关联查询上的一些区别,相比之下mysql只有一种表连接类型:嵌套循环连
- 本文实例讲述了Python设计模式之观察者模式。分享给大家供大家参考,具体如下:观察者模式是一个软件设计模式,一个主题对象包涵一系列依赖他的
- Mako是一个高性能的Python模板库,它的语法和API借鉴了很多其他的模板库,如Django、Jinja2等等。基本用法创建模板并渲染它
- 前言在进行业务数据分析时,往往需要使用pandas计算环比、同比及增长率等指标,为了能够更加方便的进行的统计数据,整理方法如下。1.数据准备
- python绘图的包大家应该不会陌生,但是,对图的常规设置不一定会知道(其实自己也是才知道的),比如:坐标轴的字体大小、颜色设置;标题的字体
- 1.前言数据库的重要性相信大家都有所了解,作为各种数据的电子资料夹,其中可能包含了各种信息,从企业员工信息到网站访问或成交数据无所不包,甚至
- 前面简单介绍了Python列表基本操作,这里再来简单讲述一下Python元组相关操作>>> dir(tuple) #查看元
- 一、打包多个1、将需要打包的项目为anjuke_sd目录下的所有python文件,其中excute_main.py为主文件。2、生成主函数对