浅谈如何使用 github.com/kardianos/service
在实际开发过程中,有时候会遇到如何编写Go开机自启服务的需求,在linux中我们可以使用systemd来进行托管,windows下可以通过注册表来实现,mac下可以通过launchd来实现,上面的方式对于开发者来说,并不是什么困难的事情,但是对于使用者而言,是并不希望通过这么复杂的方式来达到开机自启的功能的。这个时候,作为开发者,就需要使用其他的方式来实现开机自启的功能,下面讲一个Go中,借助这个库 github.com/kardianos/service 来简化如何实现开机自启功能。
1、github.com/kardianos/service 基础介绍
1.1 kardianos/service 简介
我们先来看一看 github.com/kardianos/service 上面的自我介绍:Run go programs as a service on major platforms.
如何理解上面这句话呢,上面这句话翻译出来的意思是:"在主要平台上将Go程序作为服务运行"。
这意味着我们可以将Go编写的程序以服务的形式在主要操作系统上运行,例如Windows、Linux、macOS等。这意味着程序可以在后台持续运行,而不需要用户手动启动或停止它们。这种方式可以提高程序的可靠性和稳定性,同时也方便了程序的管理和监控。
那该如何理解服务呢?
服务(Service)是指在计算机系统中,为用户或其他程序提供某种功能的程序或进程。服务通常在后台运行,可以长时间运行,不需要用户交互,可以自动启动和停止。服务可以提供各种功能,如网络服务、数据库服务、文件共享服务等。在操作系统中,服务通常以服务进程的形式运行,可以通过系统管理工具进行管理和配置。
有了上面的了解过后,再来看看官方自己的描述。service will install / un-install, start / stop, and run a program as a service (daemon). Currently supports Windows XP+, Linux/(systemd | Upstart | SysV), and OSX/Launchd. 如何理解上面这句话呢,我说说自己的理解。
我们可以将编写好的代码打包成二进制文件后,通过
二进制文件名 + install / un-install, start / stop来运行我们的服务,程序将作为服务(守护进程)运行。目前支持Windows XP+、Linux/(systemd|Upstart|SysV)和OSX/Launchd。
Windows controls services by setting up callbacks that is non-trivial. This is very different then other systems. This package provides the same API despite the substantial differences. It also can be used to detect how a program is called, from an interactive terminal or from a service manager. 下面是我的理解:
Windows 通过设置回调来控制服务,这与其他系统非常不同。这个包提供了相同的API,尽管存在很大差异。它还可以用于检测程序是从交互式终端还是从服务管理器调用的。
看到这里的时候,我其他不太理解最后一句话,什么叫从
服务管理器调用。将在 2.2 章节中介绍。
1.2 kardianos/service 安装
安装 github.com/kardianos/service 的方式和其他方式一样。
go get github.com/kardianos/service
指定版本方式
go get github.com/kardianos/service@v1.2.2
2、kardianos/service 使用方式
以下介绍都是基于 github.com/kardianos/service@v1.2.2 进行讲解的。
2.1 kardianos/service 简单的使用
我们先来看一个简单的例子,代码如下:
package main
import (
"fmt"
"github.com/kardianos/service"
"os"
)
type SystemService struct {}
func (ss *SystemService) Start(s service.Service) error {
fmt.Println("coming Start.......")
go ss.run()
return nil
}
func (ss *SystemService) run() {
fmt.Println("coming run.......")
}
func (ss *SystemService) Stop(s service.Service) error {
fmt.Println("coming Stop.......")
return nil
}
func main() {
fmt.Println("service.Interactive()---->", service.Interactive())
svcConfig := &service.Config{
Name: "custom-service",
DisplayName: "custom service",
Description: "this is github.com/kardianos/service test case",
}
ss := &SystemService{}
s, err := service.New(ss, svcConfig)
if err != nil {
fmt.Printf("service New failed, err: %v\n", err)
os.Exit(1)
}
if len(os.Args) > 1 {
err = service.Control(s, os.Args[1])
if err != nil {
fmt.Printf("service Control 111 failed, err: %v\n", err)
os.Exit(1)
}
return
}
// 默认 运行 Run
err = s.Run()
if err != nil {
fmt.Printf("service Control 222 failed, err: %v\n", err)
os.Exit(1)
}
}
通过go run main.go得到如下结果,注意:程序并不会终止,而是阻塞住了。
service.Interactive()----> true
coming Start.......
coming run.......
实际上,kardianos/service为我们提供了下面的参数使用,我们可以通过go build -o main main.go编译得到二进制文件,然后使用下面的命令来运行服务。
# 生成开机自启服务所需要的文件,文件位置根据操作系统的不同而不用,linux在 /etc/systemd/system 或者 /lib/systemd/system 下
./main install
# 删除上面生成的文件
./main uninstall
# 开启服务
./main start
# 重启服务
./main restart
# 停止服务
./main stop
2.2 kardianos/service 如何做开机自启服务
接下来以 Linux 为例,进行讲解。其他系统大家可自行尝试。
具体的步骤如下:
1、第一步是编写代码,编写完成后,编译成二进制文件。
代码就以 2.1 中的为例。首先编译成二进制文件。
go build -o main main.go
2、运行 可执行文件。
# 这将在 /etc/systemd/system 或者 /lib/systemd/system 中生成 custom-service.service 文件
# 我这里测试的时候是在 /etc/systemd/system 中生成的
./main install
看到这里,用过systemd的朋友应该可以猜到 kardianos/service 背后是通过什么来实现开机自启的。就是通过
systemd来管理的。
3、将 custom-service.service 服务设置为开机自启.
运行下面命令将我们编写的程序设置为开机自启服务。
# 设置服务开机自启动
systemctl enable test-service.service
# 启动
systemctl start test-service.service
下面是systemctl常用的命令。
# 启动
systemctl start test-service.service
# 停止
systemctl stop test-service.service
# 设置服务开机自启动
systemctl enable test-service.service
# 查询是否自启动服务
systemctl is-enabled test-service.service
# 取消服务器开机自启动
systemctl disable test-service.service
# 列出正在运行的服务
systemctl list-units --type=service
接下来我们看看服务管理器是什么意思?
1、./main install

2、查看custom-service.service文件

3、执行systemctl start custom-service.service后,查看服务运行过程

这里就是上面
服务管理器的作用,也就是说,如何服务是手动运行的,那么service.Interactive()返回 true,比如:./main start。如何是系统管理器运行的,则返回 false,比如:systemctl start custom-service.service。
2.3 结合 cli 使用
通过上面的例子,我们大概知道了如何使用 github.com/kardianos/service 。实际使用中,一般的服务都可以通过-h来查看帮助文档,但是我们我们通过./main -h会报错,所以需要完善下代码,使我们的程序更容易使用。下面,我们一起看看,借助 github.com/urfave/cli/v2 来完成上面的需求。
package main
import (
"fmt"
"github.com/kardianos/service"
"github.com/urfave/cli/v2"
"os"
)
type SystemService struct {}
func (ss *SystemService) Start(s service.Service) error {
fmt.Println("coming Start.......")
go ss.run()
return nil
}
func (ss *SystemService) run() {
fmt.Println("coming run.......")
}
func (ss *SystemService) Stop(s service.Service) error {
fmt.Println("coming Stop.......")
return nil
}
func main() {
app := cli.NewApp()
app.Name = "custom-service"
app.Usage = "how to use custom service"
app.Commands = []*cli.Command{
{
Name: "install",
Action: ctrlAction,
},
{
Name: "uninstall",
Action: ctrlAction,
},
{
Name: "start",
Action: ctrlAction,
},
{
Name: "restart",
Action: ctrlAction,
},
{
Name: "stop",
Action: ctrlAction,
},
}
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "install",
Value: "install",
Usage: "Write the files required for startup",
},
&cli.StringFlag{
Name: "uninstall",
Value: "uninstall",
Usage: "Delete startup files",
},
&cli.StringFlag{
Name: "start",
Value: "start",
Usage: "start the service",
},
&cli.StringFlag{
Name: "stop",
Value: "stop",
Usage: "stop the service",
},
&cli.StringFlag{
Name: "restart",
Value: "restart",
Usage: "restart the service",
},
}
app.Action = startAction
app.Run(os.Args)
}
func createSystemService() (service.Service, error) {
fmt.Println("service.Interactive()---->", service.Interactive())
svcConfig := &service.Config{
Name: "custom-service",
DisplayName: "custom service",
Description: "this is github.com/kardianos/service test case",
}
ss := &SystemService{}
s, err := service.New(ss, svcConfig)
if err != nil {
return nil, fmt.Errorf("service New failed, err: %v\n", err)
}
return s, nil
}
func ctrlAction(c *cli.Context) error {
s, err := createSystemService()
if err != nil {
fmt.Printf("createSystemService failed, err: %v\n", err)
return err
}
err = service.Control(s, c.Command.Name)
if err != nil {
fmt.Printf("service Run 222 failed, err: %v\n", err)
return err
}
return nil
}
func startAction(c *cli.Context) error {
s, err := createSystemService()
if err != nil {
fmt.Printf("createSystemService failed, err: %v\n", err)
return err
}
// 默认 运行 Run
err = s.Run()
if err != nil {
fmt.Printf("service Run failed, err: %v\n", err)
return err
}
return nil
}
大家可以根据自己的需求进行开发,这里只是讲一个简单的案例而已。
编译:
go build -o main main.go
运行:
./main -h
NAME:
custom-service - how to use custom service
USAGE:
custom-service [global options] command [command options] [arguments...]
COMMANDS:
install
uninstall
start
restart
stop
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--install value Write the files required for startup (default: "install")
--uninstall value Delete startup files (default: "uninstall")
--start value start the service (default: "start")
--stop value stop the service (default: "stop")
--restart value restart the service (default: "restart")
--help, -h show help
浅谈如何使用 github.com/kardianos/service的更多相关文章
- 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6627260 在前面一篇文章浅谈Service ...
- Web Service进阶(七)浅谈SOAP Webservice和RESTful Webservice
浅谈SOAP Webservice和RESTful Webservice REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性.RE ...
- 浅谈 kubernetes service 那些事(上篇)
一.问题 首先,我们思考这样一个问题: 访问k8s集群中的pod, 客户端需要知道pod地址,需要感知pod的状态.那如何获取各个pod的地址?若某一node上的pod故障,客户端如何感知? 二.k8 ...
- 浅谈 kubernetes service 那些事 (下篇)
欢迎访问网易云社区,了解更多网易技术产品运营经验. 五.K8s 1.8 新特性--ipvs ipvs与iptables的性能差异 随着服务的数量增长,IPTables 规则则会成倍增长,这样带来的问题 ...
- Service Cloud 零基础(一)Case 浅谈
本片参考:https://resources.docs.salesforce.com/222/latest/en-us/sfdc/pdf/salesforce_case_implementation_ ...
- 浅谈服务治理、微服务与Service Mesh(三) Service Mesh与Serverless
作为本系列文章的第三篇(前两篇<浅谈服务治理.微服务与Service Mesh(一)Dubbo的前世今生>,<浅谈服务治理.微服务与Service Mesh(二) Spring Cl ...
- 浅谈angular2+ionic2
浅谈angular2+ionic2 前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别. 1. 项目所用:angular2+ionic2 ...
- 浅谈HTML5单页面架构(一)——requirejs + angular + angular-route
心血来潮,打算结合实际开发的经验,浅谈一下HTML5单页面App或网页的架构. 众所周知,现在移动Webapp越来越多,例如天猫.京东.国美这些都是很好的例子.而在Webapp中,又要数单页面架构体验 ...
- [UWP]浅谈按钮设计
一时兴起想谈谈UWP按钮的设计. 按钮是UI中最重要的元素之一,可能也是用得最多的交互元素.好的按钮设计可以有效提高用户体验,构造让人眼前一亮的UI.而且按钮通常不会影响布局,小小的按钮无论怎么改也不 ...
- URL跳转与webview安全浅谈
URL跳转与webview安全浅谈 我博客的两篇文章拼接在一起所以可能看起来有些乱 起因 在一次测试中我用burpsuite搜索了关键词url找到了某处url我测试了一下发现waf拦截了指向外域的请求 ...
随机推荐
- MySQL增加多用户及数据库
登录MYSQL(有ROOT权限),这里以ROOT身份登录: @>mysql -u root -p @>密码 首先为用户创建一个数据库(yc): mysql>create databa ...
- 在.net core中开发web页面,更新html代码刷新不生效的问题
因为在.net core之后的版本,程序都是以控制台应用程序的方式存在,所以一些老的项目升级后,会出现这样的情况, 解决方法,在nuget中引入 Microsoft.AspNetCore.Mvc.Ra ...
- Mybatis-plus常见报错
1.提示数据库(表)不存在,如图: 原因:mybatis-plus默认查询的表名字为实体类的名字User,并转小写. 解决:添加注解@TableName设置表名
- mysql对汉字排序
问题: 编写order by排序时,如果字段是汉字的话,排序会失效. 如: SELECT * FROM user ORDER BY age ASC,username DESC 此时按照username ...
- docker学习随笔
总结自https://zhuanlan.zhihu.com/p/187505981 Linux内核提供了Namespace技术来隔离PID/IPC/网络资源等,还提供了Control Group(cg ...
- 基于Mindspore2.0的GPT2预训练模型迁移教程
摘要: 这篇文章主要目的是为了让大家能够清楚如何用MindSpore2.0来进行模型的迁移. 本文分享自华为云社区<MindNLP-基于Mindspore2.0的GPT2预训练模型迁移教程> ...
- Dcat admin 多文件上传,七牛云云端上传
进入官网 Dcat Admin - Php后台开发框架 这里要选择1.x 下面来安装框架 安装完laravel之后,需要修改.env文件,设置数据库链接设置正确 安装 dcat-admin comp ...
- day06-静态资源访问&Rest风格
SpringBoot之静态资源访问&REST风格请求 1.SpringBoot静态资源访问 1.1基本介绍 只要静态资源是放在类路径下的:/static./public./resources. ...
- java中foreach循环用法详解
前言 在前面的文章中,千锋壹哥给大家讲解了for.while.do-while三种循环结构,并讲解了如何跳出循环的几种方式,比如break.continue.return等.但是截止到目前,与循环相关 ...
- Linux下学习FPGA
声明(叠甲):鄙人水平有限,本文章仅供参考. 1.环境 推荐使用 Ubuntu20.04这是我使用多个版本中最好用的一个,相关安装教程可以自行上网搜索这不再赘述,但要补充的一点的是源推荐使用中科大的源 ...